年化96%的小市值策略的选股逻辑源码来了

之前写了一篇文章是《分享一个年化96%的小市值策略》 代码是基于聚宽平台写的,后期有粉丝朋友想让花姐改成基于xtquant+MiniQMT版本,这不就来了。

这里先回顾下这个策略:

选股逻辑

1、选取中小板 399101 指数成份股作为初始池

2、剔除里面的ST股票、次新股、停牌的股、涨停跌停股、北交所和科创板的股票

3、选取流通市值最小的前100个股票

4、再选取每股收益大于0的保留前100个

5、最后在这100只中,每个行业选出一只股票,然后取市值最小的股票N个用于交易

调仓逻辑

调仓逻辑也很简单,每周二会按照选股逻辑选出6个股票,然后卖出之前持有的,买入最新的6个股票。当然如果持有的股票涨停了就会继续持有,把剩余的仓位买入新调入的股票。

止盈止损

每天在10点去根据条件判断止盈止损,这里我设置了几个条件 1、持有的股票收益>100%止盈 2、跌破成本的91%就无条件止损 3、如果中小板 399101 指数平均跌幅 > 5%,全部清仓

接下来就是这篇文章的重头戏了

选股逻辑源码

量化系统框架还没搭建好的可以先参考这篇教程,后面的代码都是基于这套框架来运行的,是必备条件。

从0到1打造一套小白也能跑得起来的量化框架_图文教程

1、获取中小综指成份股

这个还是很方便的,直接调用xtquant里的函数就可以获取了代码如下:

python 复制代码
initial_list = xtdata.get_stock_list_in_sector('中小综指') #获取指数成份股

返回值是一个包含股票代码的列表['000001.SZ', '000002.SZ', '000063.SZ', '000069.SZ',...]

2、排除 4、8、68开头的股票

这里也是基本的列表操作

python 复制代码
def filter_kcbj_stock(stock_list):
    for stock in stock_list[:]:
        if stock[0] == '4' or stock[0] == '8' or stock[:2] == '68':
            stock_list.remove(stock)
    return stock_list

3、过滤次新股 上市不足1年的直接去掉

python 复制代码
def filter_new_stock(stock_list,instrument_detail_list):
    out_list =[]
    data_list = instrument_detail_list
    for stock in stock_list:
        OpenDate = data_list[stock]['OpenDate']
        date_obj = datetime.strptime(OpenDate, "%Y%m%d")
        # 获取当前日期(不包含时间部分)
        today = datetime.today().date()
        # 只取日期部分比较
        date_obj_only = date_obj.date()

        # 计算差值
        delta_days = (today - date_obj_only).days
        if delta_days>=365:
            out_list.append(stock)

    return out_list

4、过滤ST股票 这里在接口文档没有找到可以直接获取ST股票列表的接口,所以直接根据股票名称来判断是不是ST股

python 复制代码
def filter_st_stock(stock_list,instrument_detail_list):
    out_list =[]
    data_list = instrument_detail_list
    for stock in stock_list:
        InstrumentName = data_list[stock]['InstrumentName']
        if 'st' not in InstrumentName \
        and 'ST' not in InstrumentName \
        and '*' not in InstrumentName  \
        and '退' not in InstrumentName:
            out_list.append(stock)
    return out_list

5、过滤停牌股

xtquant接口中InstrumentStatus表示合约停牌状态,<=0:正常交易

python 复制代码
def filter_paused_stock(stock_list,instrument_detail_list):
    out_list =[]
    data_list = instrument_detail_list
    for stock in stock_list:
        InstrumentStatus = data_list[stock]['InstrumentStatus']
        if InstrumentStatus<=0:
            out_list.append(stock)
    return out_list

6、获取流通市值最小的200个股票 这个方法里我同时过滤了涨跌停的股票

python 复制代码
def get_ltsz_top200(stock_list,instrument_detail_list):
    # 排除 涨停 跌停 然后获取流通市值最小的200个股票
    # 获取昨天的日期
    yesterday = datetime.today() - timedelta(days=10)
    data_list = instrument_detail_list
    temp_list=[]
    # 格式化为 YYYYMMDD
    yesterday_str = yesterday.strftime("%Y%m%d")
    for i in range(0,len(stock_list),500):
        stock_list_window = stock_list[i:i+500]
        xtdata.download_history_data2(stock_list=stock_list_window,start_time=yesterday_str,period='1d',incrementally=True)
        
    
        hq_list = xtdata.get_market_data_ex(['open','high','low','close','volume','amount','preClose'],
                                             stock_list_window, period='1d', count=1, 
                                             dividend_type='front',start_time=yesterday_str,fill_data=False)
        for stock in stock_list_window:
            FloatVolume = data_list[stock]['FloatVolume'] #流通股本
            UpStopPrice = data_list[stock]['UpStopPrice'] # 涨停价
            DownStopPrice = data_list[stock]['DownStopPrice'] # 跌停价
            hq = hq_list[stock]
            if len(hq)>0:
                close_price = hq.iloc[-1]['close']
                if close_price>DownStopPrice and close_price<UpStopPrice:
                    temp_list.append({"stock":stock,"float_amount":close_price*FloatVolume})
        
    df_temp = pd.DataFrame(temp_list)
    top_200_smallest = df_temp.nsmallest(200, 'float_amount')
    # print(top_200_smallest)
    return top_200_smallest

7、基本每股收益>0的股票

一开始下载财务数据的时候我用的是download_financial_data接口,一直没响应,有人知道是什么原因吗?后来改成download_financial_data2就没问题了。

python 复制代码
def get_eps_up_0(stock_list):
    out_list =[]
    # 取数据前请确保已下载所需要的财务数据
    xtdata.download_financial_data2(stock_list, table_list=["Income"])
    data_list = xtdata.get_financial_data(stock_list,table_list=["Income"])
    for stock in stock_list:
        data = data_list[stock]['Income']
        if len(data)>0:
            s_fa_eps_basic = data.iloc[-1]['s_fa_eps_basic'] #基本每股收益
            if s_fa_eps_basic>0:
                out_list.append(stock)
                
    return out_list

8、获取每个行业市值最小的股票

这里分了2步写的,首先是获取股票对应的申万二级行业

python 复制代码
def get_stock_industry(stock_list):
    sector_list = xtdata.get_sector_list()
    sw2_list = [s for s in sector_list if s[:3].lower()=='sw2' and '加权' not in s] #获取申万二级行业
    result_list =[]
    for sw2 in sw2_list:
        s_list = xtdata.get_stock_list_in_sector(sw2)
        for stock in stock_list:
            if stock in s_list:
                result_list.append({'stock':stock,'industry':sw2})
    
    df_industry = pd.DataFrame(result_list)
    # df_industry.to_csv("个股行业.csv")
    return df_industry

接下来就是把每个行业市值最小的股票取出来

python 复制代码
def get_top_1_industry(df_industry,df_ltsz):
    df_merge = pd.merge(df_industry,df_ltsz,how='inner',on='stock')
    result  = df_merge.loc[df_merge.groupby('industry')['float_amount'].idxmin()]
    return result

最后我们用result = df_top1_industry.nsmallest(stock_count, 'float_amount')获取市值最小的N个股票用于交易

以上就是整个策略的选股逻辑核心代码了。

相关推荐
DLYSB_11 小时前
存储运维实战:基于 Ceph Event 监听与 Python 适配器的分布式存储健康度物理声光响应架构
运维·ceph·python·报警灯
陈随易11 小时前
FFmpeg 9.0 发布,代号 Lei,音视频处理再升级
前端·后端·程序员
阿童木写作11 小时前
跨境图片翻译工具多合一,批量图片视频字幕翻译加智能抠图
人工智能·python·音视频·语音识别
阿童木写作13 小时前
Python实现Temu图片批量翻译自动化教程
运维·人工智能·python·自动化
就是一只白14 小时前
复制地理信息python版本
python
凌虚14 小时前
面向 MySQL 用户的 PostgreSQL 快速上手指南
数据库·后端·架构
看浪的路人14 小时前
第1讲:Agent 到底是什么?和 Chatbot 有什么区别
python·ai
瓦学妹15 小时前
什么是网络索引?它是如何工作的?
大数据·网络·python·网络爬虫
IT_陈寒15 小时前
Vite静态资源引用这个坑我踩得有点疼
前端·人工智能·后端
天天爱吃肉821815 小时前
商用车多体动力学实战笔记|第6篇:动力传动系统(发动机、变速箱、分动器、TCS、LSD限滑差速)
大数据·人工智能·笔记·python·嵌入式硬件·汽车