zoukankan      html  css  js  c++  java
  • 选出市值最小的n只股票,输出csv

    小市值因子是很重要的选股策略,主要意思就是,小市值的股票涨幅通常会比较大。
    具体执行的方法可以是:每周末(或每个月末)选出市值最小的10只股票,下周初(或下月初)平均资金买入,到下下周(或下下个月)再换10只,如此循环。
    本节代码可以生成所有股票最近的交易数据,按市值排序,也可以根据设置,选出市值最小的n只股票(已剔除ST、停盘、即将退市的股票)。
    思路:从新浪网站爬取所有股票的最近交易数据,按市值排序,存成csv,供参考买入、卖出。
    from urllib.request import urlopen  # python自带爬虫库
    import pandas as pd
    from datetime import datetime
    import time
    import re  # 正则表达式库
    import os  # 系统库
    import json  # python自带的json数据库
    pd.set_option('expand_frame_repr', False)  # 当列太多时不换行
    pd.set_option('display.max_rows', 500)  # 最多显示数据的行数
    
    # =====函数:从网页上抓取数据,返回抓取到的网页内容
    def get_content_from_internet(url, max_try_num=10, sleep_time=5):
        """
        使用python自带的urlopen函数,从网页上抓取数据
        :param url: 要抓取数据的网址
        :param max_try_num: 最多尝试抓取次数
        :param sleep_time: 每次抓取失败后停顿的时间
        :return: 返回抓取到的网页内容
        """
        get_success = False  # 是否成功抓取到内容
        # 抓取内容
        for i in range(max_try_num):
            try:
                content = urlopen(url=url, timeout=15).read()  # 使用python自带的库,从网络上获取信息
                get_success = True  # 成功抓取到内容
                break
            except Exception as e:
                print('抓取数据报错,次数:', i+1, '报错内容:', e)
                time.sleep(sleep_time)
    
        # 判断是否成功抓取内容
        if get_success:
            return content
        else:
            raise ValueError('使用urlopen抓取网页数据不断报错,达到尝试上限,停止程序,请尽快检查问题所在')
    
    # =====函数:从新浪获取指定股票(可多只,可以是指数)最近一个交易日的数据,整理成一定格式的DataFrame,返回这个DataFrame
    def get_today_data_from_sinajs(code_list):
        """
        返回一串股票最近一个交易日的相关数据
        从这个网址获取股票数据:http://hq.sinajs.cn/list=sh600000,sz000002,sz300001
        正常网址:https://finance.sina.com.cn/realstock/company/sh600000/nc.shtml,
        :param code_list: 一串股票代码的list,可以多个,例如[sh600000, sz000002, sz300001],
        :return: 返回一个存储股票数据的DataFrame
        """
        # 构建url
        url = "http://hq.sinajs.cn/list=" + ",".join(code_list) #先用逗号把code_list中的元素连接起来,再在前面加上http:……
    
        # 抓取数据
        content = get_content_from_internet(url)
        content = content.decode('gbk') #用gbk解码,可解码出中文;解码前是dytes,解码后是str
    
        # 将数据转换成DataFrame
        content = content.strip()  # 去掉文本前后的空格、回车等
        data_line = content.split('
    ')  # 每行是一个股票的数据,生成一个列表
        data_line = [i.replace('var hq_str_', '').split(',') for i in data_line] #去掉每行前面的冗余数据,并再次分割,形成2层列表
    #    df = pd.DataFrame(data_line, dtype='float')  #dtype='float'可生成数值型数据
        df = pd.DataFrame(data_line)   #这里只生成DF,转float放在下面
    
        # 对DataFrame进行整理
        df[0] = df[0].str.split('="')   # df[0]是取“0”列
        df['stock_code'] = df[0].str[0].str.strip()
        df['stock_name'] = df[0].str[-1].str.strip()
        df['candle_end_time'] = df[30] + ' ' + df[31]  # 股票市场的K线,是普遍以当跟K线结束时间来命名的
        df['candle_end_time'] = pd.to_datetime(df['candle_end_time'])
        rename_dict = {1: 'open', 2: 'pre_close', 3: 'close', 4: 'high', 5: 'low', 6: 'buy1', 7: 'sell1',
                       8: 'volume', 9: 'amount', 32: 'status'}  # 自己去对比数据,会有新的发现;10~29是买卖五档盘口的数据
        # 其中volume单位是股,amount单位是元
        df.rename(columns=rename_dict, inplace=True)
        #挑选需要转化的列,转化为float
        df[['open', 'high', 'low', 'close', 'pre_close', 'amount','volume', 'buy1', 'sell1']] 
        = df[['open', 'high', 'low', 'close', 'pre_close', 'amount', 'volume', 'buy1', 'sell1']].astype('float')
        df['status'] = df['status'].str.strip('";') #在status列,去掉冗余的‘";’字符
    
        df = df[['stock_code', 'stock_name', 'candle_end_time', 'open', 'high', 'low', 'close', 'pre_close', 'amount',
                 'volume', 'buy1', 'sell1', 'status']] #重新规定列顺序
    
        return df
    
    # =====函数:从新浪获取所有股票最近一个交易日的数据,返回一个DF
    def get_all_today_stock_data_from_sina_marketcenter():
        """
        http://vip.stock.finance.sina.com.cn/mkt/#stock_hs_up
        从新浪网址的上述的网址,逐页获取最近一个交易日所有股票的数据
        :return: 返回一个存储股票数据的DataFrame
        """
    
        # ===数据网址
        raw_url = 'http://vip.stock.finance.sina.com.cn/quotes_service/api/json_v2.php/Market_Center.getHQNodeData?page=%s' 
                  '&num=80&sort=symbol&asc=1&node=hs_a&symbol=&_s_r_a=sort'
        page_num = 1
    
        # ===存储数据的DataFrame
        all_df = pd.DataFrame()
    
        # ===获取上证指数最近一个交易日的日期。此段代码在课程视频中没有,之后补上的
        df = get_today_data_from_sinajs(code_list=['sh000001'])
        sh_date = df.iloc[0]['candle_end_time'].date()  # 上证指数最近交易日
    
        # ===开始逐页遍历,获取股票数据
        while True:
            # 构建url
            url = raw_url % (page_num)
            print('开始抓取页数:', page_num)
    
            # 抓取数据
            content = get_content_from_internet(url)
            content = content.decode('gbk')
    
            # 判断页数是否为空
            if 'null' in content:
                print('抓取到页数的尽头,退出循环')
                break
    
            # 通过正则表达式,给key加上引号
            content = re.sub(r'(?<={|,)([a-zA-Z][a-zA-Z0-9]*)(?=:)', r'"1"', content)
            # 将数据转换成dict格式
            content = json.loads(content)   #此时,content转化为list,其中的元素是dict
    
            # 将数据转换成DataFrame格式
            df = pd.DataFrame(content, dtype='float')
            # 对数据进行整理
            # 重命名;总市值单位是万元,流通值单位是万元,成交量volume单位股数,成交额amount单位是元
            rename_dict = {'symbol': '股票代码', 'name': '股票名称', 'open': '开盘价', 'high': '最高价', 'low': '最低价','trade': '收盘价',
                           'settlement': '前收盘价', 'volume': '成交量', 'amount': '成交额', 'mktcap':'总市值','nmc':'流通值'}
            df.rename(columns=rename_dict, inplace=True) # 没映射的列,还是保留原来的列名,即列数不会减少
            # 添加交易日期
            # df['交易日期'] = pd.to_datetime(datetime.now().date())  # 课程视频中使用的是本行代码
            df['交易日期'] = pd.to_datetime(sh_date)  # 在课程视频中使用的是上一行代码,现在改成本行代码,程序更加稳健
            # df中的字段,还包括:mktcap(总市值)、nmc(流通值)、per(本益比,类似市盈率)、pb(市净率)、turnoverratio(换手率)
            # 取需要的列
            df = df[['股票代码', '股票名称', '交易日期', '开盘价', '最高价', '最低价', '收盘价',
                     '前收盘价', '成交量', '成交额','总市值','流通值']]
    
    
            # 合并数据
            all_df = all_df.append(df, ignore_index=True)
    
            # 将页数+1
            page_num += 1
            time.sleep(1)
    
        # ===将当天停盘的股票删除,此段代码在课程视频中没有,之后补上的
        all_df = all_df[all_df['开盘价'] - 0 > 0.00001]
        all_df.reset_index(drop=True, inplace=True)
    
        # ===返回结果
        return all_df
    
    # 以下为主程序
    # ===参数设定
    select_stock_num = 10  # 选股数量
    
    # 获取今天所有的股票数据
    df = get_all_today_stock_data_from_sina_marketcenter()
    
    # 函数中已删除当天停盘的股票,这里再删除ST和即将退市的股票
    df = df[df['股票名称'].str.contains('ST')== False] # 删除ST股票
    df = df[df['股票名称'].str.contains('退') == False] #删除即将退市股票
    
    df['排名'] = df['总市值'].rank() # 根据总市值的排名
    df.to_csv(r'C:UsersloriDesktopstockinvestproject1datadjl_data根据当前总市值选股all_stock_rank.csv',
              encoding='gbk',mode='w',index=False)
    df.sort_values(by='总市值',inplace=True) # 根据总市值排序
    
    df_select = df[['交易日期','股票代码', '股票名称', '总市值','流通值','排名','收盘价']]
    df_select = df_select.iloc[:select_stock_num]
    df_select.to_csv(r'C:UsersloriDesktopstockinvestproject1datadjl_data根据当前总市值选股select_stock.csv',
              encoding='gbk',mode='w',index=False)
    

      

     
  • 相关阅读:
    HDU 2899 Strange fuction
    HDU 2899 Strange fuction
    HDU 2199 Can you solve this equation?
    HDU 2199 Can you solve this equation?
    Java实现 LeetCode 700 二叉搜索树中的搜索(遍历树)
    Java实现 LeetCode 700 二叉搜索树中的搜索(遍历树)
    Java实现 LeetCode 700 二叉搜索树中的搜索(遍历树)
    Java实现 LeetCode 699 掉落的方块(线段树?)
    Java实现 LeetCode 699 掉落的方块(线段树?)
    Java实现 LeetCode 699 掉落的方块(线段树?)
  • 原文地址:https://www.cnblogs.com/djlbolgs/p/12541213.html
Copyright © 2011-2022 走看看