qff.price.query 源代码

# coding :utf-8
#
# The MIT License (MIT)
#
# Copyright (c) 2016-2019 XuHaiJiang/QFF
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

"""
从数据库中查询股票价格数据
"""

import pandas as pd
from typing import Dict, Optional
from datetime import datetime
from bson.regex import Regex
from qff.tools.mongo import DATABASE
from qff.tools.date import get_pre_trade_day, is_trade_day, get_real_trade_date, util_date_valid, util_time_valid
from qff.tools.utils import util_code_tolist
from qff.tools.logs import log
from qff.frame.context import context, RUN_STATUS

__all__ = ['get_price', 'get_bars', 'get_stock_list', 'get_stock_name', 'get_index_stocks', 'get_block_stock',
           'get_mtss', 'get_all_securities', 'get_security_info', 'get_st_stock', 'get_paused_stock',
           'get_stock_block', 'history', 'attribute_history', 'get_index_name', 'get_industry_stocks']


[文档]def get_price(security, start=None, end=None, freq='daily', fields=None, skip_paused=False, fq='pre', count=None, market='stock'): """ 获取历史数据,可查询一支或者多个标的的行情数据, 按天或者按分钟,返回数据格式为 DataFrame :param security: 单只标的代码或标的代码列表,标的为股票、指数、ETF等,本参数不能为空. :param count: 返回的结果集的行数, 即表示获取 end_date 之前几个freq的数据,与 start 二选一,不可同时使用. :param start: 查询开始时间,与 count 二选一,不可同时使用. 1. 如果 count 和 start_date 参数都没有, 则 start 等于 end. 2. 如果 count 和 start_date 参数都设置, 则 start 生效,返回结果会截取最后count数量的记录。 3. 当取分钟数据时, 时间可以精确到分钟, 比如: 传入datetime.datetime(2015, 1, 1, 10, 0, 0) 或者 '2015-01-01 10:00:00' 4. 当取分钟数据时, 如果只传入日期, 则日内时间是当日的 09:30:00 - 15:00:00 5. 当取天数据时, 传入的日内时间会被忽略 :param end: 查询结束时间, 默认是当前日期, **注意:** 当取分钟数据时, 如果 end 只有日期,则日内时间等同于 15:00:00. :param freq: 单位时间长度, 现在支持['daily', '1d', 'day', '1min', '5min', '15min', '30min', '60min', '1m', '5m', '15m', '30m', '60m'], :param fields: 选择要获取的行情数据字段, 默认是None,表示['open', 'close', 'high', 'low', 'vol','amount'] 这几个标准字段, 指数另外支持[’up_count', 'down_count']。 :param skip_paused: 是否跳过不交易日期(包括停牌, 未上市或者退市后的日期). 如果不跳过, 停牌时会使用停牌前收盘价数据填充。 **关于停牌:** 因为此API可以获取多只股票的数据, 可能有的股票停牌有的没有, 为了保持时间轴的一致,我们默认没有跳过停牌的日期 :param fq: 复权选项: 'pre', 前复权; None,不复权, 返回实际价格;'post',后复权 :param market: 市场类型,目前支持[“stock", ”index","ETF"], 默认“stock". :type security: str or list :type count: int :type start: str、datetime.datetime or datetime.date :type end: str、datetime.datetime or datetime.date :type freq: str :type fields: str or list :type skip_paused: bool :type fq: str or None :type market: str :return: 请注意, 为了方便比较一只股票的多个属性, 同时也满足对比多只股票的一个属性的需求, 我们在security参数是一只股票和多只股票 时返回的结构完全不一样. * 如果是一支股票, 则返回[pandas.DataFrame]对象, 行索引是date(分钟级别数据为datetime), 列索引是行情字段名字. * 如果是多支股票, 则返回[pandas.DataFrame]对象,行索引是['date', 'code'],或['datetime', 'code'] :rtype: DataFrame or None :example: :: # 获取股票000001当天的日数据 df = get_price('000001') # 获得000001的2020年01月的分钟数据, 只获取open+close字段 df = get_price('000001', start='2020-01-01', end='2020-01-31 23:00:00', frequency='1m', fields=['open', 'close']) # 获取获得000001在2020年01月31日前2个交易日的数据 df = get_price('000001', count = 2, end='2015-01-31', freq='daily', fields=['open', 'close']) # 获得000001的2020年12月1号14:00-2020年12月2日12:00的分钟数据 df = get_price('000001', start='2020-12-01 14:00:00', end_date='2020-12-02 12:00:00', freq='1m') # 获取多只股票 panel = get_price(get_index_stocks('000903')) # 获取中证100的所有成分股的当天日数据, 返回一个[pandas.DataFrame] """ log.debug('调用get_price' + str(locals()).replace('{', '(').replace('}', ')')) # 1、参数合法性判断 if market not in ['stock', 'index', 'etf'] or \ freq not in ['daily', '1d', 'day', '1min', '5min', '15min', '30min', '60min', '1m', '5m', '15m', '30m', '60m'] or fq not in ['pre', 'post', None]: log.error('get_price:参数错误!对照API文档检查market、freq、fq等参数的合法性!') return None if market != 'stock' and skip_paused: log.error('get_price:参数错误!对照API文档检查market、skip_paused、fq等参数的合法性!') return None # 2、开始和结束时间计算 if end is None: end = datetime.now().strftime('%Y-%m-%d %H:%M:%S') if not is_trade_day(end[:10]): end = get_real_trade_date(end) else: if not util_date_valid(end) and not util_time_valid(end): log.error('get_price:参数错误!对照API文档检查end参数的合法性!') return None if start is None: if count is None: start = end else: start = get_pre_trade_day(end, count - 1, freq) else: if not util_date_valid(start) and not util_time_valid(start): log.error('get_price:参数错误!对照API文档检查start参数的合法性!') return None if freq in ['daily', '1d', 'day']: start = str(start)[:10] end = str(end)[:10] freq = 'day' date_index = 'date' else: start = str(start) end = str(end) if len(start) == 10: start = '{} 09:30:00'.format(start) if len(end) == 10: end = '{} 15:00:00'.format(end) if len(freq) < 4: freq = freq + 'in' date_index = 'datetime' # 3、其他参数初始化 code = util_code_tolist(security) coll = DATABASE.get_collection(market + '_' + freq[-3:]) field_list = ['open', 'close', 'low', 'high', 'vol', 'amount'] if market == 'index': field_list += ['up_count', 'down_count'] # 4、field参数计算 if fields is None: projection = {"_id": 0, "code": 1, date_index: 1, 'open': 1, 'close': 1, 'low': 1, 'high': 1, 'vol': 1, 'amount': 1} else: if isinstance(fields, str): fields = [fields] if isinstance(fields, list): base_fields = [elem for elem in fields if elem in field_list] if len(base_fields) == 0: log.error(f"get_price:参数fields不合法!,应该{field_list}为列表!") if market == 'stock' and skip_paused and 'vol' not in base_fields: base_fields.append('vol') projection = dict.fromkeys(base_fields, 1) prefix = { "_id": 0, "code": 1, date_index: 1, } projection = dict(**prefix, **projection) else: log.error("get_price:参数fields不合法!,应该为字符串或字符串列表!") return None # 5、数据库查询 filter = { 'code': {'$in': code}, date_index: { "$gte": start, "$lte": end }, } if freq != 'day': filter['type'] = freq cursor = coll.find(filter, projection=projection, batch_size=10000) data = pd.DataFrame([item for item in cursor]) if len(data) == 0: log.debug("get_price未查询到数据") return None # 5、数据清洗 data.drop_duplicates([date_index, 'code'], inplace=True) if 'vol' in data.columns.values: data.vol = data.vol.apply(lambda x: int(x * 100)) # 股票成交数量不能有小数 if 'amount' in data.columns.values: data.amount = data.amount.apply(lambda x: round(x, 2)) # 股票成交额保留两位小数 # 6、处理skip_paused if market == 'stock' and skip_paused: data = data.query('vol>1').copy() if fields and 'vol' not in fields: data = data.drop('vol', axis=1) # 7、对股票进行复权计算 if market == 'stock' and fq in ['pre', 'post']: cursor = DATABASE.stock_adj.find( { 'code': { '$in': code }, "date": { "$lte": end[:10], "$gte": start[:10] } }, {"_id": 0}, batch_size=10000 ) adj = pd.DataFrame([item for item in cursor]) if len(adj) > 0: if date_index == 'datetime': data['date'] = data.datetime.apply(lambda x: str(x)[:10]) # 生成日期 data.set_index(['date', 'code'], inplace=True) adj.set_index(['date', 'code'], inplace=True) data = data.join(adj, how='left') if fq == 'pre': data['qfq'] = data['qfq'].fillna(1) # 前复权空值填1,倒序 cof = data['qfq'] else: data['hfq'] = data['hfq'].fillna(method='ffill') # # 后复权空值填最后一个系数 cof = data['hfq'] for col in ['open', 'high', 'low', 'close']: if col in data.columns.values: data[col] = round(data[col] * cof, 2) data.reset_index(inplace=True) data.drop(['qfq', 'hfq'], axis=1, inplace=True) if date_index == 'datetime': data.drop('date', axis=1, inplace=True) else: log.debug("get_price获取复权因子失败!返回未复权值") if count is not None: data = data.groupby(['code'], as_index=False).tail(count) if len(code) == 1: data = data.drop('code', axis=1).set_index(date_index) else: data.set_index([date_index, 'code'], inplace=True) return data
[文档]def history(count, unit='1d', field='close', security_list=None, skip_paused=False, fq='pre'): # type: (int, str, str, list, bool, str ) -> Optional[pd.DataFrame] """ 回测/模拟专用API 获取历史数据,可查询多个股票的单个数据字段,返回数据格式为 DataFrame 当取天数据时, 不包括当天的, 即使是在收盘后;分钟数据不包括当前分钟的数据,没有未来 :param count: 数量, 返回的结果集的行数 :param unit: 单位时间长度,现在支持['daily', '1d', 'day', '1min', '5min', '15min', '30min', '60min', '1m', '5m', '15m', '30m', '60m'] :param field: 要获取的数据类型,只能是一个值,包含:['open', ' close', 'low', 'high', 'vol', 'amount'] :param security_list: 要获取数据的股票列表,None 表示查询 context.universe 中所有股票的数据 :param skip_paused: 是否跳过不交易日期(包括停牌). 如果不跳过, 停牌时会使用停牌前的数据填充。 :param fq: 复权选项。'pre':前复权;'post':后复权;None:不复权 :return: [pandas.DataFrame]对象, 行索引是datetime字符串, 列索引是股票代号. """ if context.status != RUN_STATUS.RUNNING: print("history为回测模拟专用API函数,只能在策略运行过程中使用!") return None log.debug('调用history' + str(locals()).replace('{', '(').replace('}', ')')) code = security_list if security_list is not None else context.universe code = util_code_tolist(code) if len(code) == 0: log.error("history():参数security_list为空并且context.universe为空!") return None if field not in ['open', 'close', 'high', 'low', 'vol', 'amount']: log.error("history():参数field 错误!") return None if unit in ['daily', '1d', 'day']: end_date = context.previous_date data = get_price(code, end=end_date, fields=field, freq=unit, count=count, skip_paused=skip_paused, fq=fq) if data is not None: if len(code) > 1: data = data[field].reset_index().pivot(index='date', columns='code', values=field) else: data = data[field] elif unit in ['1min', '5min', '15min', '30min', '60min', '1m', '5m', '15m', '30m', '60m']: end_date = context.current_dt data = get_price(code, end=end_date, fields=field, freq=unit, count=count + 1, fq=fq) if data is not None: if len(code) > 1: data = data[field].reset_index.pivot(index='datetime', columns='code', values=field) else: data = data[field] data = data.iloc[:-1] else: log.error("history():unit 参数错误!") return None return data
[文档]def attribute_history(security, count, unit='1d', fields=None, fq='pre'): """ 回测/模拟专用API 查看某一支股票的历史数据, 可以选这只股票的多个属性, 默认跳过停牌日期. 当取天数据时, 不包括当天的, 即使是在收盘后;分钟数据不包括当前分钟的数据,没有未来; :param security: 股票代码 :param count: 数量, 返回的结果集的行数 :param unit: 单位时间长度,现在支持['daily', '1d', 'day', '1min', '5min', '15min', '30min', '60min', '1m', '5m', '15m', '30m', '60m'] :param fields: 包含:['open', ' close', 'low', 'high', 'vol', 'amount'] :param fq: 复权选项: pre-前复权 None-不复权 post-后复权 :return: 返回[pandas.DataFrame]对象,行索引是datetime字符串, 列索引是属性名字. :type security: str or list :type count: int :type unit: str :type fields: str or list :type fq: str or None """ if context.status != RUN_STATUS.RUNNING: print("attribute_history为回测模拟专用API函数,只能在策略运行过程中使用!") return None log.debug('调用attribute_history' + str(locals()).replace('{', '(').replace('}', ')')) if fields is None: fields = ['open', 'close', 'high', 'low', 'vol', 'amount'] if unit in ['daily', '1d', 'day']: end_date = context.previous_date data = get_price(security, end=end_date, fields=fields, freq=unit, count=count, skip_paused=True, fq=fq) if data is not None: data = data[fields] elif unit in ['1m', '5m', '15m', '30m', '60m']: end_date = context.current_dt data = get_price(security, end=end_date, fields=fields, freq=unit, count=count + 1, skip_paused=True, fq=fq) if data is not None: data = data[fields].iloc[:-1] else: log.error("attribute_history(): unit 参数错误!") return None return data
[文档]def get_bars(security, count, unit='1d', fields=None, include_now=False, end_dt=None, fq_ref_date=None, market='stock'): # type: (list, int, str, Optional[list], bool, Optional[str], Optional[str], str) -> Optional[pd.DataFrame] """ **函数暂未实现** 获取各种时间周期的 bar 数据, bar 的分割方式与主流股票软件相同, 而且支持返回当前时刻所在 bar 的数据; get_bars 开盘时取的bar高开低收都是当天的开盘价,成交量成交额为0; get_bars 没有跳过停牌选项,所获取的数据都是不包含停牌的数据,如果bar个数少于count个,则返回实际个数,并不会填充。 :param security: 标的代码或列表,支持一个或多个标的 :param count: 大于0的整数,表示获取bar的个数。如果行情数据的bar不足count个,返回的长度则小于count个数。 :param unit: bar的时间单位, 支持标准bar,包括['1m', '5m', '15m', '30m', '60m', '1d'] :param fields: 获取数据的字段, 支持如下值:['date', 'open', 'close', 'high', 'low', 'vol', 'amount'],默认为None,表示全部字段。 :param include_now: 取值True 或者False。 表示是否包含当前bar, 比如策略时间是9:33,unit参数为5m,如果 include_now=True,则返回9:30-9:33这个分钟 bar。 :param end_dt: 查询的截止时间,支持的类型为None或str。默认值为None * 在回测/模拟环境下默认为context.current_dt * 在其他环境下默认为datetime.now() * 由于bar的最小单位是一分钟,所以end_dt的秒没有什么意义,会被替换为0,例如:"2019-11-22 9:35:23" 和 "2019-11-22 9:35:00" 是一样的。 :param fq_ref_date: 复权基准日期,支持的类型为str或None,为None时为不复权数据。 * 回测/模拟环境中默认为 context.current_dt * 在投研环境下默认为datetime.now() * 如果输入 fq_ref_date = None, 则获取到的是不复权的数据 * 如果想获取后复权的数据,可以将fq_ref_date 指定为一个股票IPO之前很早的日期,比如 datetime.date(1990, 1, 1) * 定点复权,以某一天价格点位为参照物,进行的前复权或后复权。 * 设置为datetime.datetime.now()即返回前复权数据。 * 设置为context.current_dt返回动态复权数据, :param market: 市场类型,目前支持[“stock", ”index","ETF"], 默认“stock". :return: * 若security为字符串格式的标的代码时,返回pandas.DataFrame,dataframe 的index是一个日期字符串 * 若security为list格式的标的代码时,返回pandas.DataFrame,dataframe 的index是一个MultiIndex :example: :: # 获取平安银行最近5天数据,包括context.current_date df = get_bars('000001', 5, unit='1d',fields=['open','close'],include_now=True) # 设置复权基准日为 2018-01-05 , 取得的最近5条包括 end_dt 的天数据 get_bars('600507',5,unit='1d', fields=['date','open', 'high', 'low', 'close'],include_now=True, end_dt='2018-01-05 11:00:00', fq_ref_date='2018-01-05') """ """ log.debug('调用get_bar' + str(locals()).replace('{', '(').replace('}', ')')) # 1、参数合法性判断 if market not in ['stock', 'index', 'etf'] or \ unit not in ['daily', '1d', 'day', '1min', '5min', '15min', '30min', '60min', '1m', '5m', '15m', '30m', '60m']: log.error('get_bar:参数错误!对照API文档检查market、unit参数的合法性!') return None # 2. end_dt if end_dt is None: if context.status == RUN_STATUS.RUNNING: end_dt = context.current_dt else: end_dt = datetime.now().strftime('%Y-%m-%d %H:%M:%S') else: if not isinstance(end_dt, str) or (not util_date_valid(end_dt) and not util_time_valid(end_dt)): log.error('get_bar:参数错误!对照API文档检查end_dt参数的合法性!') return None if context.run_type == RUN_TYPE.BACK_TEST and context.status == RUN_STATUS.RUNNING: pass elif context.run_type == RUN_TYPE.SIM_TRADE and context.status == RUN_STATUS.RUNNING: pass else: pass # 2. 获取当天日期,决定使用历史数据还是实时数据 today = datetime.now().strftime('%Y-%m-%d %H:%M:%S') if is_trade_day(today[:10]) and end_dt[:10]: pass """ return None
[文档]def get_all_securities(date=None, market='stock', df=False): """ 获取平台支持的所有股票信息 :param date: 查询日期, 用于获取某日期还在上市的股票信息. 默认值为 None, 表示获取当日的股票信息. 1. 特定参数“all”, 表示获取所有日期的上市股票信息。 2. 特定参数“delist", 表示获取所有退市股票信息 3. **建议使用时添加上指定date** :param market: 用来过滤securities的类型,目前支持的type仅有['stock', 'index', 'etf] :param df: 返回格式,若是True, 返回[pandas.DataFrame], 否则返回一个仅包含标的代码的list, 默认是False. :type date: str :type market: str :type df: bool :return: [pandas.DataFrame or list]返回标的列表 :example: :: get_all_securities()[:2] 返回: ['000001', '000002'] 当日市场交易的所有股票列表 get_all_securities(df=True)[:2] 返回: --- name start end type 000001 平安银行 1991-04-03 2200-01-01 stock 000002 万 科A 1991-01-29 2200-01-01 stock name: 中文名称 start: 上市日期 end: 退市日期(股票是最后一个交易日,不同于摘牌日期),如果没有退市则为2200-01-01; type: 类型,stock(股票),index(指数),etf(场内ETF基金) """ if market not in ['stock', 'index', 'etf']: log.error('get_all_securities:参数错误!market参数不合法!') return None coll = DATABASE.get_collection(f'{market}_list') # filter = {} filter: Dict[str, any] = {} if market == 'stock': if date is None: filter['end'] = '2200-01-01' elif util_date_valid(date): filter['end'] = {"$gt": date} filter['start'] = {"$lte": date} elif date == 'delist': filter['end'] = {"$lt": '2200-01-01'} elif date != 'all': log.error('get_all_securities:参数错误!date参数不合法!') return None elif market == 'index': if date is None: # date = datetime.date().strftime('%Y-%m-%d') pass elif util_date_valid(date): filter['start'] = {"$lte": date} elif date is not None and date != 'all': log.error('get_all_securities:参数错误!date参数不合法!') return None cursor = coll.find(filter, {'_id': 0}) if df: return pd.DataFrame([item for item in cursor]).set_index('code').sort_index() else: return sorted([item["code"] for item in cursor])
[文档]def get_security_info(code, market='stock'): """ 获取股票的信息. :param code: 证券代码 :type code: 字符串 :param market: 用来过滤code的类型,目前支持的type仅有['stock', 'index', 'etf] :type market: 字符串 :return: 一个字典对象, 有如下key值: 1. code: 股票代码 2. name: 中文名称 3. start: 上市日期, 字符串类型 4. end: 退市日期(股票是最后一个交易日,不同于摘牌日期), 如果没有退市则为2200-01-01 :example: :: # 获取股票000001的上市时间 start_date = get_security_info('000001').start print(start) """ coll = DATABASE.get_collection(market + '_list') cursor = coll.find({'code': code}, {'_id': 0}) try: rtn = cursor[0] except IndexError: rtn = {'code': code, 'name': '代码不存在', 'start': '', 'end': ''} return rtn
def get_stock_list(date=None): """ 获取股票列表 :param date: 在该日期上市的股票,如果为空,则取上一个交易日日期 :return list: 返回股票代码列表 """ return get_all_securities(date=date)
[文档]def get_index_stocks(index, date=None): """ 获取一个指数给定日期的成分股列表.目前仅支持: * '000016' :上证50 * '000852' :中证1000 * '000905' :中证500 * '000906' :中证800 * '000300' :沪深300 * '000010' :上证180 * '000688' : 科创50abc :param index: 字符串,一个指数代码,如‘000300’ :param date: 字符串,查询日期, 如'2015-10-15'. 默认为None,指当前日期 :return: 返回股票代码的list """ if index not in ['000016', '000852', '000905', '000906', '000300', '000010', '000688']: log.error("get_index_stocks: 参数index仅支持 ['000016', '000852', '000905', '000906','000300', '000010', '000688']") return None filter: Dict[str, any] = {"index": index} if date is None: filter["end"] = '2200-01-01' elif util_date_valid(date): filter['end'] = {"$gt": date} filter['start'] = {"$lte": date} else: log.error('get_index_stocks:参数错误!date参数不合法!') return None coll = DATABASE.index_stock cursor = coll.find(filter, {"_id": 0, "code": 1}) return [item["code"] for item in cursor]
[文档]def get_industry_stocks(industry, date=None): """ 获取申万一级行业给定日期的成分股列表.目前仅支持(申万I级): * '801010' :农林牧渔 * '801030' :基础化工 * '801040' :钢铁 * '801050' :有色金属 * '801080' :电子 * '801110' :家用电器 * '801120' :食品饮料 * '801130' :纺织服饰 * '801140' :轻工制造 * '801150' :医药生物 * '801160' :公用事业 * '801170' :交通运输 * '801180' :房地产 * '801200' :商贸零售 * '801210' :社会服务 * '801230' :综合 * '801710' :建筑材料 * '801720' :建筑装饰 * '801730' :电力设备 * '801740' :国防军工 * '801750' :计算机 * '801760' :传媒 * '801770' :通信 * '801780' :银行 * '801790' :非银金融 * '801880' :汽车 * '801890' :机械设备 * '801950' :煤炭 * '801960' :石油石化 * '801970' :环保 * '801980' :美容护理 :param industry: 字符串,一个指数代码,如‘801010’ :param date: 字符串,查询日期, 如'2015-10-15'. 默认为None,指当前日期 :return: 返回股票代码的list """ if industry not in ['801010', '801030', '801040', '801050', '801080', '801110', '801120', '801130', '801140', '801150', '801160', '801170', '801180', '801200', '801210', '801230', '801710', '801720', '801730', '801740', '801750', '801760', '801770', '801780', '801790', '801880', '801890', '801950', '801960', '801970', '801980']: log.error("get_industry_stocks: 参数industry仅支持(申万I级)") return None filter: Dict[str, any] = {"index": industry} if date is None: filter["end"] = '2200-01-01' elif util_date_valid(date): filter['end'] = {"$gt": date} filter['start'] = {"$lte": date} else: log.error('get_industry_stocks:参数错误!date参数不合法!') return None coll = DATABASE.industry_stock cursor = coll.find(filter, {"_id": 0, "code": 1}) return [item["code"] for item in cursor]
[文档]def get_stock_name(code=None, date=None): """ 获取股票名称 :param code: 股票代码,支持list, 如果为空,则返回所有股票 :param date: 查询日期,如果为空,则取上一个交易日日期 :return dict: 返回股票代码与股票名称的字典 """ filter: Dict[str, any] = {} if code is not None: code = util_code_tolist(code) filter['code'] = {'$in': code} if date is None: filter['end'] = "2200-01-01" elif util_date_valid(date): filter['end'] = {"$gt": date} filter['start'] = {"$lte": date} else: log.error('get_stock_name:参数错误!date参数不合法!') return None if 'stock_name' in DATABASE.list_collection_names(): coll = DATABASE.stock_name else: coll = DATABASE.stock_list cursor = coll.find(filter, {"_id": 0, "code": 1, "name": 1}) rtn = {item["code"]: item["name"] for item in cursor} # 修复stock_list和stock_name两个结合数据来源不一致造成的bug if code is not None and len(code) > len(rtn): diff = {i: "-" for i in code if i not in rtn.keys()} rtn = dict(**rtn, **diff) return rtn
[文档]def get_index_name(code=None): """ 获取指数名称 :param code: 指数代码,支持list, 如果为空,则返回所有指数 :return dict: 返回股票代码与股票名称的字典 """ collections = DATABASE.index_list if code is not None: code = util_code_tolist(code) cursor = collections.find( { "code": { '$in': code }, }, {"_id": 0, "code": 1, "name": 1}, ) else: cursor = collections.find({}, {"_id": 0, "code": 1, "name": 1}) return {item["code"]: item["name"] for item in cursor}
[文档]def get_st_stock(code=None, date=None): """ 获取ST股票代码和名称 :param code: 股票代码,支持list, 如果为空,则查询所有股票 :param date: 查询日期,如果为空,则取最近交易日日期 :return dict: 返回股票代码与股票名称的字典 """ filter: Dict[str, any] = {} if code is not None: code = util_code_tolist(code) filter['code'] = {'$in': code} if date is None: filter['end'] = "2200-01-01" elif util_date_valid(date): filter['end'] = {"$gt": date} filter['start'] = {"$lte": date} else: log.error('get_st_stock:参数错误!date参数不合法!') return None filter['name'] = Regex(u".*ST.*", "i") if 'stock_name' in DATABASE.list_collection_names(): coll = DATABASE.stock_name else: coll = DATABASE.stock_list cursor = coll.find(filter, {"_id": 0, "code": 1, "name": 1}) return {item["code"]: item["name"] for item in cursor}
[文档]def get_paused_stock(code=None, date=None): """ 获取停牌的股票代码 :param code: 股票代码,支持list, 如果为空,则查询所有股票 :param date: 查询日期,如果为空,则取最近交易日日期 :return list: 返回股票代码列表 """ filter = {} if code is not None: if isinstance(code, str): code = [code] elif not isinstance(code, list): log.error("参数code不合法!,应该为字符串或列表!") return None filter['code'] = {'$in': code} if date is None: date = datetime.now().strftime('%Y-%m-%d') if not is_trade_day(date): date = get_real_trade_date(date) elif util_date_valid(date): if not is_trade_day(date): date = get_real_trade_date(date) else: log.error("参数date输入不合法!") return None filter['date'] = date filter['vol'] = {'$lt': 1} coll = DATABASE.stock_day projection = {"_id": 0, "code": 1} cursor = coll.find(filter=filter, projection=projection) return [item["code"] for item in cursor]
[文档]def get_block_stock(block): """ 根据板块名称检索对应的股票代码 :param block: 板块名称 :return: 板块对应的股票代码列表 :type block: str :rtype: list 板块名称汇总:: blockname = [ 300ESG,300周期,300非周,3D打印,5G概念,BIPV概念,C2M概念,CIPS概念,CXO概念,ETC概念 HJT电池,IP变现,MCU芯片,MSCIA50,MSCI中盘,MSCI成份,MiniLED,NFT概念,NMN概念,OLED概念 PPP模式,PVDF概念,QFII新进,QFII重仓,RCS概念,ST板块,一带一路,三代半导,上海自贸,上证180 上证380,上证50,上证中盘,上证创新,上证治理,上证混改,上证红利,上证超大,不活跃股,专精特新 业绩预升,业绩预增,业绩预降,东数西算,两年新股,个人持股,中俄贸易,中创100,中华A80,中字头 中小100,中小300,中小银行,中盘价值,中盘成长,中证100,中证200,中证央企,中证红利,中证龙头 久不分红,乡村振兴,亏损股,云游戏,云科技,云计算,互联金融,人工智能,人脑工程,人造肉 代糖概念,仿制药,低价股,低市净率,低市盈率,体育概念,保险新进,保险重仓,信创,信息安全 信托重仓,债转股,储能,元宇宙,充电桩,光伏,光刻机,免疫治疗,免税概念,养老概念 养老金,内地低碳,军民融合,农业50,农村金融,冷链物流,分拆上市,分散染料,创业300,创业创新 创业大盘,创业板50,创业板指,创业蓝筹,创医药,创成长,创投概念,创新100,创科技,创质量 券商重仓,券商金股,化肥,北上重仓,北交所,北京冬奥,区块链,区块链50,医废处理,医美概念 半导体50,博彩概念,卫星导航,即将解禁,参股新股,参股金融,双创50,发可转债,口罩防护,可燃冰 台资背景,含B股,含GDR,含H股,含可转债,员工持股,商誉减值,回购计划,固态电池,国产软件 国信价值,国开持股,国证价值,国证农业,国证基建,国证大宗,国证成长,国证服务,国证治理,国证红利 国证芯片,国资云,国防军工,土地流转,在线消费,地下管网,地摊经济,地热能,垃圾分类,培育钻石 基因概念,基金减仓,基金增仓,基金独门,基金重仓,壳资源,外资背景,大数据,大盘价值,大盘成长 大盘股,大飞机,天然气,央企100,央企改革,央视50,婴童概念,字节跳动,安防服务,定增股 定增预案,家庭医生,密集调研,富时A50,小盘价值,小盘成长,小米概念,工业互联,工业大麻,工业母机 工业气体,已高送转,幽门菌,微利股,微盘股,恒大概念,成渝特区,户数减少,户数增加,扣非亏损 投资时钟,抗癌,拟减持,拟增持,持续增长,换电概念,摘帽,操作系统,数字孪生,数字货币 数据中心,整体上市,新冠检测,新冠药,新型烟草,新材料,新硬件,新能源车,新进成份,新零售 无人机,无人驾驶,无线耳机,昨成交20,昨收活跃,昨日上榜,昨日振荡,昨日涨停,昨日跌停,昨日较弱 昨日较强,昨日连板,昨日首板,昨曾涨停,昨曾跌停,昨高换手,智慧城市,智慧政务,智能交通,智能医疗 智能家居,智能机器,智能电网,智能电视,智能穿戴,最近复牌,最近多板,最近异动,最近闪拉,最近闪跌 有机硅,机构吸筹,板块趋势,核污防治,核电核能,次新开板,次新股,次新超跌,次新预增,武汉规划 民企100,民营医院,民营银行,氟概念,氢能源,氮化镓,水产品,水利建设,污水处理,汽车拆解 汽车电子,汽车芯片,沪深300,油气改革,泛珠三角,活跃股,海南自贸,海外业务,海峡西岸,消费100 消费电子,涉矿概念,深次新股,深注册制,深证100,深证300,深证价值,深证创新,深证成指,深证成长 深证治理,深证红利,烟草概念,燃料电池,物业管理,物联网,特斯拉,特高压,猪肉,环保50 环渤海,生物疫苗,生物质能,电商概念,电子纸,电子身份,电解液,白酒概念,百元股,百度概念 皖江区域,盐湖提锂,知识产权,石墨烯,破净资产,破发行价,碳中和,碳纤维,磷概念,社保新进 社保重仓,种业,科创50,科创信息,科技100,租购同权,稀土永磁,稀缺资源,空气治理,粤港澳 精选指数,绩优股,维生素,绿色建筑,绿色照明,绿色电力,网红经济,网络游戏,职业教育,聚氨酯 股东减持,股东增持,股权分散,股权激励,股权转让,股权集中,胎压监测,能源互联,腾讯概念,腾讯济安 航运概念,节能,芯片,苹果概念,草甘膦,虚拟现实,虫害防治,融资增加,融资融券,行业龙头 被举牌,装配建筑,装饰园林,要约收购,证金汇金,资源优势,赛马概念,超导概念,超清视频,超级电容 跨境电商,轮动趋势,辅助生殖,边缘计算,近已解禁,近期弱势,近期强势,近期新低,近期新高,远程办公 连续亏损,送转潜力,送转超跌,透明工厂,通达信88,配股股,配股预案,重组股,重组预案,量子科技 金融科技,钛金属,钠电池,钴金属,铁路基建,银河99,锂电池,锂矿,镍金属,长三角 长株潭,阿里概念,陆股通减,陆股通增,降解塑料,雄安新区,页岩气,预制菜,预计扭亏,预计转亏 预高送转,风沙治理,风能,风险提示,食品安全,高商誉,高市净率,高市盈率,高校背景,高端装备 "高股息股","高融资盘","高贝塔值","高负债率","高质押股","鸡肉","鸿蒙概念","黄金概念" ] """ collections = DATABASE.stock_block cursor = collections.find( {"blockname": block, "type": 'zs'}, {"_id": 0, "code": 1}, ) return [item["code"] for item in cursor]
[文档]def get_stock_block(code): """ 根据股票代码检索对应的block名称 """ collections = DATABASE.stock_block cursor = collections.find( {"code": code}, {"_id": 0, "blockname": 1}, ) return [item["blockname"] for item in cursor]
[文档]def get_mtss(security_list, start_date, end_date, fields=None): """ 获取股票的融资融券信息. 获取一只或者多只股票在一个时间段内的融资融券信息 :param security_list: 一只股票代码或者一个股票代码的 list :param start_date: 开始日期, 一个字符串 :param end_date: 结束日期, 一个字符串 :param fields: 字段名或者 list, 可选. 默认为 None, 表示取全部字段, 各字段含义如下: ================== ==================== 字段名 含义 ================== ==================== date 日期 sec_code 股票代码 fin_value 融资余额(元) fin_buy_value 融资买入额(元) fin_refund_value 融资偿还额(元) sec_value 融券余量(股) sec_sell_value 融券卖出量(股) sec_refund_value 融券偿还股(股) ================== ==================== :return: 返回一个 pandas.DataFrame 对象,默认的列索引为取得的全部字段. 如果给定了 fields 参数, 则列索引与给定的 fields 对应. """ if start_date is None: start_date = '2010-03-31' if end_date is None: end_date = datetime.now().strftime('%Y-%m-%d') if isinstance(security_list, str): security_list = [security_list] filter = { 'code': { '$in': security_list }, 'date': { '$gte': start_date, '$lte': end_date } } if fields is None: projection = {'_id': 0} elif isinstance(fields, list): projection = dict.fromkeys(fields, 1) prefix = { "_id": 0, "code": 1, "date": 1 } projection = dict(**prefix, **projection) else: projection = None cursor = DATABASE.stock_mtss.find(filter, projection) return pd.DataFrame([item for item in cursor])