├── WindAdapter ├── tests │ ├── __init__.py │ ├── test_suite.py │ ├── test_api.py │ └── test_windpy.py ├── data_dict.csv ├── settings.ini ├── __init__.py ├── enums.py ├── custom_logger.py ├── utils.py ├── data_provider.py ├── helper.py ├── api.py └── factor_loader.py ├── requirements ├── py3.txt └── py2.txt ├── MANIFEST.in ├── example ├── factor_loader.py ├── tutorial.md └── tutorial.ipynb ├── LICENSE ├── setup.py ├── .travis.yml ├── .gitignore └── README.md /WindAdapter/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /WindAdapter/data_dict.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iLampard/WindAdapter/HEAD/WindAdapter/data_dict.csv -------------------------------------------------------------------------------- /requirements/py3.txt: -------------------------------------------------------------------------------- 1 | mock 2 | numpy>=1.10.1 3 | pandas>=0.18.0 4 | logbook 5 | argcheck 6 | python-decouple>=3.0 7 | toolz 8 | x-utils -------------------------------------------------------------------------------- /requirements/py2.txt: -------------------------------------------------------------------------------- 1 | enum34>=1.0.4 2 | mock 3 | numpy 4 | pandas>=0.18.0 5 | logbook 6 | argcheck 7 | python-decouple>=3.0 8 | toolz 9 | x-utils -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include MANIFEST.in 2 | include .coveragerc 3 | include requirements/py2.txt 4 | include requirements/py3.txt 5 | recursive-include WindAdapter *.csv 6 | recursive-include . *.md 7 | -------------------------------------------------------------------------------- /WindAdapter/settings.ini: -------------------------------------------------------------------------------- 1 | [settings] 2 | 3 | # Data dict path settings 4 | DATA_DICT_PATH=data_dict.csv 5 | DATA_DICT_PATH_TYPE_ABS=False 6 | 7 | # Multi-Index series header 8 | MULTI_INDEX_NAMES = date,secID 9 | DF_COL_NAME = factor -------------------------------------------------------------------------------- /example/factor_loader.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from WindAdapter import factor_load 4 | 5 | ret = factor_load('2014-01-01', '2014-01-15', 'FULL_OHLC_DAY', sec_id='ashare', is_index=True, freq='D', save_file='ashare.csv') 6 | 7 | 8 | print factor_load('2014-01-01', '2014-01-10', 'close', sec_id='ashare', is_index=True, freq='D', save_file='close.pkl') 9 | -------------------------------------------------------------------------------- /WindAdapter/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | from WindAdapter.api import get_universe 5 | from WindAdapter.api import get_live 6 | from WindAdapter.api import factor_load 7 | from WindAdapter.api import factor_help 8 | from WindAdapter.api import factor_details_help 9 | from WindAdapter.api import reset_data_dict_path 10 | 11 | __all__ = ['version', 12 | 'get_universe', 13 | 'get_live', 14 | 'factor_load', 15 | 'factor_help', 16 | 'factor_details_help', 17 | 'reset_data_dict_path', 18 | 'data_provider'] 19 | 20 | 21 | def version(): 22 | return __version__ 23 | 24 | 25 | __version__ = '0.4.0' 26 | -------------------------------------------------------------------------------- /WindAdapter/tests/test_suite.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import os 4 | import sys 5 | import unittest 6 | thisFilePath = os.path.abspath(__file__) 7 | sys.path.append(os.path.sep.join(thisFilePath.split(os.path.sep)[:-3])) 8 | from WindAdapter.tests.test_api import TestApi 9 | 10 | 11 | def test(): 12 | print('Python ' + sys.version) 13 | suite = unittest.TestSuite() 14 | tests = unittest.TestLoader().loadTestsFromTestCase(TestApi) 15 | suite.addTests(tests) 16 | 17 | res = unittest.TextTestRunner(verbosity=3).run(suite) 18 | if len(res.errors) >= 1 or len(res.failures) >= 1: 19 | sys.exit(-1) 20 | else: 21 | sys.exit(0) 22 | 23 | 24 | if __name__ == "__main__": 25 | test() 26 | -------------------------------------------------------------------------------- /WindAdapter/enums.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | from enum import Enum 5 | from enum import IntEnum 6 | 7 | 8 | class StrEnum(str, Enum): 9 | pass 10 | 11 | 12 | class FreqType(StrEnum): 13 | MIN1 = 'min1' 14 | MIN5 = 'min5' 15 | MIN10 = 'min10' 16 | EOD = 'D' 17 | EOW = 'W' 18 | EOM = 'M' 19 | EOSY = 'S' 20 | EOY = 'Y' 21 | 22 | 23 | class OutputFormat(IntEnum): 24 | MULTI_INDEX_DF = 0 25 | PIVOT_TABLE_DF = 1 26 | 27 | 28 | class Header(StrEnum): 29 | NAME = 'name' 30 | TENOR = 'tenor' 31 | API = 'api' 32 | INDICATOR = 'indicator' 33 | FREQ = 'period' 34 | PRICEADJ = 'priceadj' 35 | UNIT = 'unit' 36 | TRADEDATE = 'tradeDate' 37 | CYCLE = 'cycle' 38 | EXPLANATION = 'explanation' 39 | TYPE = 'type' 40 | REPORTADJ = 'reportadj' 41 | MULTIFACTORS = 'multifactors' 42 | 43 | 44 | class WindDataType(IntEnum): 45 | WSS_TYPE = 0 46 | WSD_TYPE = 1 47 | 48 | 49 | class LogLevel(StrEnum): 50 | INFO = 'info' 51 | WARNING = 'warining' 52 | CRITICAL = 'critical' 53 | NOTSET = 'notset' -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import io 4 | import sys 5 | 6 | import numpy as np 7 | from setuptools import find_packages 8 | from setuptools import setup 9 | 10 | PACKAGE = 'WindAdapter' 11 | NAME = 'WindAdapter' 12 | VERSION = '0.4.0' 13 | DESCRIPTION = 'Windpy data adapter' 14 | AUTHOR = 'iLampard, RoxanneYang, bella21' 15 | URL = 'https://github.com/iLampard/WindAdapter' 16 | LICENSE = 'MIT' 17 | 18 | if sys.version_info > (3, 0, 0): 19 | requirements = "requirements/py3.txt" 20 | else: 21 | requirements = "requirements/py2.txt" 22 | 23 | setup(name=NAME, 24 | version=VERSION, 25 | description=DESCRIPTION, 26 | author=AUTHOR, 27 | url=URL, 28 | include_package_data=True, 29 | packages=find_packages(), 30 | package_data={'': ['*.csv']}, 31 | install_requires=io.open(requirements, encoding='utf8').read(), 32 | include_dirs=[np.get_include()], 33 | classifiers=['Programming Language :: Python', 34 | 'Programming Language :: Python :: 2.7', 35 | 'Programming Language :: Python :: 3.5', 36 | 'Programming Language :: Python :: 3.6']) 37 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | - "3.5" 5 | - "3.6" 6 | # command to install dependencies 7 | install: 8 | # We do this conditionally because it saves us some downloading if the 9 | # version is the same. 10 | - wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh 11 | - bash miniconda.sh -b -p $HOME/miniconda 12 | - export PATH="$HOME/miniconda/bin:$PATH" 13 | - hash -r 14 | - conda config --set always_yes yes --set changeps1 no 15 | - conda update -q conda 16 | # Useful for debugging any issues with conda 17 | - conda info -a 18 | # Replace dep1 dep2 ... with your dependencies 19 | - conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION 20 | - source activate test-environment 21 | - if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then 22 | conda install enum34; 23 | fi 24 | - conda install coverage 25 | - conda install numpy 26 | - conda install scipy 27 | - conda install pandas 28 | - conda install toolz 29 | - pip install IPython 30 | - pip install logbook 31 | - pip install python-decouple 32 | - pip install mock 33 | - pip install argcheck 34 | - pip install matplotlib 35 | - pip install x-utils 36 | - pip install coveralls 37 | # command to run tests 38 | script: 39 | - coverage run WindAdapter/tests/test_suite.py 40 | after_success: 41 | - coveralls 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | -------------------------------------------------------------------------------- /WindAdapter/custom_logger.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # ref: https://github.com/iLampard/AlgoTrading/blob/master/AlgoTrading/Utilities/Logger.py 4 | 5 | from logbook import (Logger, 6 | StreamHandler, 7 | FileHandler, 8 | set_datetime_format) 9 | import logbook 10 | import sys 11 | from WindAdapter.enums import LogLevel 12 | 13 | 14 | class CustomLogger(object): 15 | def __init__(self, 16 | log_level=LogLevel.INFO, 17 | format_str='[{record.time:%Y-%m-%d %H:%M:%S}] - {record.channel} - {record.level_name} ' 18 | '- {record.message}'): 19 | self.logger = Logger('WindAdapter') 20 | set_datetime_format('local') 21 | StreamHandler(sys.stdout, format_string=format_str).push_application() 22 | FileHandler('WindAdapter.log', bubble=True, format_string=format_str).push_application() 23 | self.set_level(log_level) 24 | 25 | def set_level(self, log_level): 26 | if log_level.lower() == LogLevel.INFO: 27 | self.logger.level = logbook.INFO 28 | elif log_level.lower() == LogLevel.WARNING: 29 | self.logger.level = logbook.WARNING 30 | elif log_level.lower() == LogLevel.CRITICAL: 31 | self.logger.level = logbook.CRITICAL 32 | elif log_level.lower() == LogLevel.NOTSET: 33 | self.logger.level = logbook.NOTSET 34 | 35 | def info(self, msg): 36 | self.logger.info(msg) 37 | 38 | def warning(self, msg): 39 | self.logger.warning(msg) 40 | 41 | def critical(self, msg): 42 | self.logger.critical(msg) 43 | 44 | -------------------------------------------------------------------------------- /WindAdapter/utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import pickle 4 | import pandas as pd 5 | from IPython.display import display 6 | import functools 7 | import datetime 8 | 9 | 10 | def save_data_to_file(data, save_file_name): 11 | """ 12 | :param data: pd.DataFrame, data to be saved 13 | :param save_file_name: str, *.* 14 | :return: 15 | """ 16 | 17 | save_file_type = save_file_name.split('.')[1] 18 | if save_file_type == 'csv': 19 | data.to_csv(save_file_name, encoding='gbk') 20 | elif save_file_type == 'pkl': 21 | pkl_dump_data(data, save_file_name) 22 | else: 23 | raise NotImplementedError 24 | 25 | 26 | def pkl_dump_data(data, pkl_file_name, protocol=-1): 27 | """ 28 | :param data: any type 29 | :param pkl_file_name: str, *.pkl 30 | :param protocol: int, optional, protocol in saving pickle 31 | :return: 32 | """ 33 | pkl_file = open(pkl_file_name, 'wb') 34 | pickle.dump(data, pkl_file, protocol) 35 | pkl_file.close() 36 | return 37 | 38 | 39 | def py_assert(condition, exception_type, msg): 40 | if not condition: 41 | raise exception_type(msg) 42 | 43 | 44 | def handle_wind_query_exception(logger): 45 | """ 46 | :param logger: logging, a logging object 47 | :return: decorator, wraps exception loggers 48 | """ 49 | 50 | def decorator(query_func): 51 | @functools.wraps(query_func) 52 | def wrapper(*args, **kwargs): 53 | try: 54 | return query_func(*args, **kwargs) 55 | except Exception as e: 56 | logger.critical('Exception in function {0} -- {1}'.format(query_func.__name__, e)) 57 | 58 | return wrapper 59 | 60 | return decorator 61 | 62 | 63 | def print_table(table, name=None, fmt=None): 64 | """ 65 | Pretty print a pandas DataFrame. 66 | Uses HTML output if running inside Jupyter Notebook, otherwise 67 | formatted text output. 68 | Parameters 69 | ---------- 70 | table : pandas.Series or pandas.DataFrame 71 | Table to pretty-print. 72 | name : str, optional 73 | Table name to display in upper left corner. 74 | fmt : str, optional 75 | Formatter to use for displaying table elements. 76 | E.g. '{0:.2f}%' for displaying 100 as '100.00%'. 77 | Restores original setting after displaying. 78 | """ 79 | 80 | if isinstance(table, pd.Series): 81 | table = pd.DataFrame(table) 82 | 83 | if fmt is not None: 84 | prev_option = pd.get_option('display.float_format') 85 | pd.set_option('display.float_format', lambda x: fmt.format(x)) 86 | 87 | if name is not None: 88 | table.columns.name = name 89 | 90 | display(table) 91 | 92 | if fmt is not None: 93 | pd.set_option('display.float_format', prev_option) 94 | 95 | 96 | def date_convert_2_str(date, fmt='%Y-%m-%d'): 97 | if isinstance(date, datetime.datetime): 98 | return date.strftime(fmt) 99 | -------------------------------------------------------------------------------- /example/tutorial.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ## 使用 5 | 6 | ##### factor_load 7 | ``` python 8 | from WindAdapter import factor_load 9 | 10 | # def factor_load(start_date, end_date, factor_name, save_file=None, **kwargs): 11 | """ 12 | :param start_date: str, 读取因子数据的开始日期 13 | :param end_date: str, 读取因子数据的结束日期 14 | :param factor_name: str, 因子名称,不区分大小写 15 | :param save_file: str, optional, 保存数据的文件名,可写成 '*.csv' 或者 '*.pkl' 16 | :param kwargs: dict, optional 17 | 18 | freq: str, optional, 因子数据的频率, 可选'M', 'W', 'S', 'Y', 参见enums.py - FreqType 19 | tenor: str, optional, 因子数据的周期, 对于截面数据(如换手率,收益率),需要给定数据区间(向前), 可选数字+FreqType, 如'3M' 20 | sec_id, str/list, optional, 股票代码或者是指数代码 21 | output_data_format: enum, optional, 参见enums.py - FreqType 22 | MULTI_INDEX_DF: multi-index DataFrame, index=[date, secID], value = factor 23 | PIVOT_TABLE_DF: DataFrame, index=date, columns = secID 24 | is_index: bool, optional, True: 输入的sec_id是指数,实际需要读取的是该指数成分股的因子数据, 25 | False: 直接读取sec_id的因子数据 26 | :return: pd.DataFrame 整理好的因子数据 27 | """ 28 | 29 | # 读取 2014年上半年 000001.SZ和000002.SZ的PB数据, 并保存成csv格式(默认数据频率为月频,数据格式为multi-index DataFrame) 30 | factor_load('2014-01-01', '2014-07-10', 'PB', sec_id=['000001.SZ', '000002.SZ'], is_index=False, save_file='PB.csv') 31 | 32 | # 读取全市场 2016年1月的每日收盘价,并保存成pickle格式 33 | factor_load('2014-01-01', '2014-07-10', 'close', sec_id='fullA', is_index=True, freq='D', save_file='close.pkl') 34 | 35 | # 读取沪深300成分股从2014年1月至3月,频率为每月(freq=M)的季度(tenor='3M')收益, 并保存成csv格式 36 | factor_load('2014-01-01', '2014-03-31', 'return', sec_id='000300.SH', is_index=True, freq='M', tenor='3M', save_file='HS300_return_1Q.csv') 37 | 38 | 39 | ``` 40 | *Note*: 返回的数据最近的日期等于入参中的end_date,前推的日期为根据频率(freq)和end_date往前推算的交易日 41 | 42 |
43 | 44 | ##### get_universe 45 | 46 | ``` python 47 | from WindAdapter import get_universe 48 | 49 | # def get_universe(index_id, date=None) 50 | """ 51 | :param index_id: str, 可以为指数代码或者'fullA'(指全市场股票),不区分大小写 52 | :param date: str, optional, YYYYMMDD/YYYY-MM-DD,默认为None,即返回最近交易日的成分股列表 53 | :return: list, 成分股列表 54 | """ 55 | 56 | # 读取指数成分股 57 | hs300_comp = get_universe(index_id='000300.SH', date='20170103') 58 | 59 | # 读取全市场股票 60 | full_mkt = get_universe(index_id='fullA') 61 | ``` 62 |
63 | 64 | ##### reset_data_dict_path 65 | 66 | ``` python 67 | from WindAdapter import reset_data_dict_path 68 | 69 | # def reset_data_dict_path(path, path_type_abs) 70 | """ 71 | :param index_id: str, 可以为指数代码或者'fullA'(指全市场股票),不区分大小写 72 | :param date: str, optional, YYYYMMDD/YYYY-MM-DD,默认为None,即返回最近交易日的成分股列表 73 | :return: list, 成分股列表 74 | """ 75 | reset_data_dict_path(path='C:\\data_dict_perso.csv', path_type_abs=True) 76 | ``` 77 |
78 | 79 | ##### factor_help / factor_details_help 80 | 81 | ``` python 82 | from WindAdapter import factor_help, factor_details_help 83 | 84 | """ 85 | :return: 返回定义的数据字典(简易版和详细版) 86 | """ 87 | factor_help() 88 | 89 | factor_details_help() 90 | 91 | ``` 92 | 93 |
94 | 95 | 96 | 97 | ##### reset_log_level 98 | ``` python 99 | from WindAdapter import reset_log_level 100 | 101 | """ 102 | :return: 设置WindAdapter函数输出信息的等级, 项目默认为'info'等级 103 | """ 104 | reset_log_level('critical') 105 | 106 | ``` 107 | 108 |
109 | 110 | ##### version 111 | 112 | ``` python 113 | from WindAdapter import version 114 | 115 | """ 116 | :return: 当前WindAdapter的版本号 117 | """ 118 | version() 119 | 120 | ``` 121 | 122 | 123 | 124 | 125 | ## 依赖 126 | ``` python 127 | numpy 128 | pandas 129 | python-decouple 130 | WindPy 131 | ``` 132 | 133 | ## 安装 134 | 135 | ``` python 136 | pip install WindAdapter 137 | ``` 138 | -------------------------------------------------------------------------------- /WindAdapter/data_provider.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import pandas as pd 4 | from xutils import (Calendar, 5 | Date, 6 | Period) 7 | 8 | try: 9 | from WindPy import w 10 | except ImportError: 11 | pass 12 | 13 | 14 | class WindRunner: 15 | def __init__(self): 16 | try: 17 | w.start() 18 | except NameError: 19 | pass 20 | 21 | def __del__(self): 22 | try: 23 | w.stop() 24 | except AttributeError: 25 | pass 26 | except NameError: 27 | pass 28 | 29 | 30 | class WindDataProvider: 31 | WIND_RUNNER = WindRunner() 32 | 33 | def __init__(self): 34 | pass 35 | 36 | @staticmethod 37 | def force_throw_err(raw_data, func_name): 38 | if raw_data.ErrorCode != 0: 39 | raise ValueError('{0}: {1}'.format(raw_data.Data[0], func_name)) 40 | elif len(raw_data.Data) == 0: 41 | raise ValueError('{0}: empty data returned'.format(func_name)) 42 | 43 | @staticmethod 44 | def get_universe(index_id, date=None, output_weight=False): 45 | index_id = index_id.lower() 46 | try: 47 | if index_id == 'fulla' or index_id == 'ashare': 48 | code = 'a001010100000000' 49 | params = 'sectorid=' + code + ';field=wind_code' if date is None \ 50 | else 'date=' + str(date) + ';sectorid=' + code 51 | raw_data = w.wset('sectorconstituent', params) 52 | else: 53 | short_params = 'windcode=' + index_id 54 | params = short_params if date is None else short_params + ';date=' + str(date) 55 | raw_data = w.wset('IndexConstituent', params) 56 | WindDataProvider.force_throw_err(raw_data, 'WindDataProvider.get_universe') 57 | if output_weight: 58 | return pd.DataFrame(data=raw_data.Data[raw_data.Fields.index('i_weight')], 59 | index=raw_data.Data[raw_data.Fields.index('wind_code')], 60 | columns=['weight']) 61 | else: 62 | return raw_data.Data[raw_data.Fields.index('wind_code')] 63 | except NameError: 64 | pass 65 | 66 | @staticmethod 67 | def forward_date(date, tenor, date_format='%Y-%m-%d'): 68 | try: 69 | start_date = Date.strptime(date, date_format) 70 | sse_cal = Calendar('China.SSE') 71 | ret = sse_cal.advanceDate(start_date, Period('-' + tenor), endOfMonth=True) 72 | # 此处返回的是上一期期末日期,再向后调整一天,以避免区间日期重叠 73 | ret = sse_cal.advanceDate(ret, Period('1b')) 74 | return str(ret) 75 | except NameError: 76 | pass 77 | 78 | @staticmethod 79 | def biz_days_list(start_date, end_date, freq): 80 | try: 81 | dates = w.tdays(start_date, end_date, 'period=' + freq) 82 | WindDataProvider.force_throw_err(dates, 'WindDataProvider.biz_days_list') 83 | return dates.Data[0] 84 | except NameError: 85 | pass 86 | 87 | @staticmethod 88 | def query_data(api, sec_id, indicator, extra_params=None, start_date=None, end_date=None): 89 | if api == 'w.wsd': 90 | ret = eval(api)(sec_id, indicator, start_date, end_date, extra_params) 91 | elif api == 'w.wss': 92 | ret = eval(api)(sec_id, indicator, extra_params) 93 | elif api == 'w.wsi': 94 | ret = eval(api)(sec_id, indicator, start_date, end_date, extra_params) 95 | elif api == 'w.wsq': 96 | ret = eval(api)(sec_id, indicator) 97 | else: 98 | raise ValueError('WindDataProvider.query_data: unknown type of api') 99 | 100 | WindDataProvider.force_throw_err(ret, 'WindDataProvider.query_data') 101 | return ret 102 | -------------------------------------------------------------------------------- /WindAdapter/helper.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import datetime 4 | import os 5 | 6 | import numpy as np 7 | import pandas as pd 8 | from decouple import config 9 | 10 | from WindAdapter.enums import Header 11 | from WindAdapter.enums import OutputFormat 12 | 13 | DATA_DICT_PATH = config('DATA_DICT_PATH', default='data_dict.csv') 14 | DATA_DICT_PATH_TYPE_ABS = config('DATA_DICT_PATH_TYPE_ABS', default=False, cast=bool) 15 | 16 | INDEX_NAME = config('MULTI_INDEX_NAMES', default='date,secID') 17 | COL_NAME = config('DF_COL_NAME', default='factor') 18 | 19 | 20 | class WindQueryHelper: 21 | def __init__(self, data_dict_path=DATA_DICT_PATH, path_type_abs=DATA_DICT_PATH_TYPE_ABS): 22 | try: 23 | if not path_type_abs: 24 | current_dir = os.path.dirname(os.path.abspath(__file__)) 25 | path = os.path.join(current_dir, data_dict_path) 26 | self.data_dict_path = path 27 | else: 28 | self.data_dict_path = data_dict_path 29 | self._data_dict = pd.read_csv(self.data_dict_path, index_col=0, encoding='gbk') 30 | except ValueError: 31 | raise ValueError('data_dict fails to load') 32 | 33 | @property 34 | def data_dict(self): 35 | return self._data_dict 36 | 37 | @staticmethod 38 | def _split_params(params): 39 | main_params = params[[Header.API, Header.EXPLANATION, Header.INDICATOR]] 40 | extra_params = params.drop([Header.API, Header.EXPLANATION, Header.INDICATOR, Header.TYPE]) 41 | extra_params[Header.TENOR.value] = np.nan 42 | extra_params[Header.FREQ.value] = 'M' 43 | return main_params, extra_params 44 | 45 | def get_query_params(self, factor_name=None): 46 | try: 47 | self.data_dict.index = self.data_dict.index.str.lower() 48 | factor_params = self.data_dict.loc[factor_name.lower()] 49 | except: 50 | raise ValueError( 51 | 'WindQueryHelper.get_query_params: failed to find params for factor {0}, check factor name spelling'.format( 52 | factor_name)) 53 | main_params, extra_params = WindQueryHelper._split_params(factor_params) 54 | main_params[Header.API] = 'w.' + main_params[Header.API] 55 | 56 | return main_params, extra_params 57 | 58 | @staticmethod 59 | def convert_2_multi_index(df): 60 | df = df.copy() 61 | df = df.stack() 62 | df = pd.DataFrame(df) 63 | df.index.names = INDEX_NAME.split(',') 64 | df.columns = [COL_NAME] 65 | return df 66 | 67 | @staticmethod 68 | def reformat_wind_data(raw_data, date, output_data_format=OutputFormat.PIVOT_TABLE_DF, multi_factors=False): 69 | if not multi_factors: 70 | ret = pd.DataFrame(data=raw_data.Data, 71 | columns=raw_data.Codes, 72 | index=[date.strftime('%Y-%m-%d')]) 73 | if output_data_format == OutputFormat.MULTI_INDEX_DF: 74 | ret = WindQueryHelper.convert_2_multi_index(ret) 75 | elif 'windcode' not in raw_data.Fields: 76 | ret = pd.DataFrame(data=np.array(raw_data.Data).T, 77 | index=pd.MultiIndex.from_product([raw_data.Codes, [date.strftime('%Y-%m-%d')]], 78 | names=['secID', 'date']), 79 | columns=[raw_data.Fields]) 80 | else: 81 | # ret = pd.DataFrame(data=np.array(raw_data.Data).T, 82 | # index=pd.MultiIndex.from_arrays([raw_data.Times, raw_data.Codes*len(raw_data.Times)], 83 | # names=['date', 'secID']), 84 | # columns=raw_data.Fields) 85 | ret = pd.DataFrame(data=np.array(raw_data.Data[2:]).T, 86 | index=pd.MultiIndex.from_arrays([raw_data.Data[raw_data.Fields.index('windcode')], 87 | raw_data.Times], 88 | names=['secID', 'date']), 89 | columns=[field for field in raw_data.Fields if field != 'time' and field != 'windcode']) 90 | return ret 91 | 92 | @staticmethod 93 | def latest_report_date(date): 94 | month = date.month 95 | if month <= 4: 96 | date = datetime.datetime(date.year - 1, 9, 30) 97 | elif month <= 8: 98 | date = datetime.datetime(date.year, 3, 31) 99 | elif month <= 11: 100 | date = datetime.datetime(date.year, 6, 30) 101 | else: 102 | date = datetime.datetime(date.year, 9, 30) 103 | return date 104 | -------------------------------------------------------------------------------- /WindAdapter/api.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import os 4 | import datetime 5 | import pandas as pd 6 | from toolz import merge 7 | from argcheck import expect_types 8 | from WindAdapter.factor_loader import FactorLoader 9 | from WindAdapter.utils import save_data_to_file 10 | from WindAdapter.utils import print_table 11 | from WindAdapter.utils import handle_wind_query_exception 12 | from WindAdapter.custom_logger import CustomLogger 13 | from WindAdapter.data_provider import WindDataProvider 14 | from WindAdapter.helper import WindQueryHelper 15 | from WindAdapter.enums import OutputFormat 16 | 17 | LOGGER = CustomLogger() 18 | WIND_DATA_PRODIVER = WindDataProvider() 19 | WIND_QUERY_HELPER = WindQueryHelper() 20 | 21 | 22 | def reset_log_level(log_level): 23 | """ 24 | :param log_level: enum, 可选择'info', 'critical' 'notset' 25 | :return: 设置WindAdapter函数输出信息的等级, 项目默认为'info'等级 26 | """ 27 | LOGGER.critical('Reset path of data dict to {0}'.format(log_level)) 28 | LOGGER.set_level(log_level) 29 | 30 | 31 | def reset_data_dict_path(path, path_type_abs): 32 | """ 33 | :param path: str, 自定义的data_dict 路径 34 | :param path_type_abs: str, True: 路径为绝对路径, False: 路径为相对路径 35 | :return: data_dict的路径被修改 36 | """ 37 | LOGGER.critical('Reset path of data dict to {0}'.format(path)) 38 | os.environ['DATA_DICT_PATH'] = path 39 | os.environ['DATA_DICT_PATH_TYPE_ABS'] = str(path_type_abs) 40 | return 41 | 42 | 43 | @handle_wind_query_exception(LOGGER) 44 | def get_universe(index_id, date=None, output_weight=False): 45 | """ 46 | :param index_id: str, 可以为指数代码或者'fullA' or 'ashare'(指全市场股票),不区分大小写 47 | :param date: str, optional, YYYYMMDD/YYYY-MM-DD,默认为None,即返回最近交易日的成分股列表 48 | :param output_weight: bool, optional, 是否返回对应的个股权重 49 | :return: 如果output_weight=False, 返回list, 成分股列表 50 | 如果output_weight=True, 返回DataFrame 51 | """ 52 | LOGGER.info('Loading the constituent stocks of index {0} at date {1}'. 53 | format(index_id, datetime.date.today() if date is None else date)) 54 | ret = WindDataProvider.get_universe(index_id, date, output_weight) 55 | LOGGER.info('Number of the loaded constituent stocks is {0}'.format(len(ret))) 56 | return ret 57 | 58 | 59 | @handle_wind_query_exception(LOGGER) 60 | def get_live(sec_id, block_size=400): 61 | """ 62 | :param sec_id: list, wind股票代码,如果是全市场,可输入'fulla'或者'ashare' 63 | :param block_size: 内部调用wsq接口一次提取的数量,默认400支 64 | :return: pd.DataFrame, index=sec id, header = [rt_open,rt_high,rt_low,rt_last,rt_vol,rt_amt,rt_vol_ratio,rt_pct_chg_5min] 65 | """ 66 | factor = FactorLoader(start_date=None, 67 | end_date=None, 68 | factor_name='LIVE', 69 | sec_id=sec_id, 70 | block_size=block_size) 71 | ret = factor.load_data() 72 | return ret 73 | 74 | 75 | @handle_wind_query_exception(LOGGER) 76 | @expect_types(factor_name=(str, list)) 77 | def factor_load(start_date, end_date, factor_name, save_file=None, **kwargs): 78 | """ 79 | :param start_date: str, 读取因子数据的开始日期 80 | :param end_date: str, 读取因子数据的结束日期 81 | :param factor_name: str, 因子名称,不区分大小写 82 | :param save_file: str, optional, 保存数据的文件名,可写成 '*.csv' 或者 '*.pkl' 83 | :param kwargs: dict, optional 84 | 85 | freq: str, optional, 因子数据的频率, 可选'M', 'W', 'S', 'Y', 参见enums.py - FreqType 86 | tenor: str, optional, 因子数据的周期, 对于截面数据(如换手率,收益率),需要给定数据区间(向前), 可选数字+FreqType, 如'3M' 87 | sec_id, str/list, optional, 股票代码或者是指数代码 88 | output_data_format: enum, optional, 参见enums.py - FreqType 89 | MULTI_INDEX_DF: multi-index DataFrame, index=[date, secID], value = factor 90 | PIVOT_TABLE_DF: DataFrame, index=date, columns = secID 91 | is_index: bool, optional, True: 输入的sec_id是指数,实际需要读取的是该指数成分股的因子数据, 92 | False: 直接读取sec_id的因子数据 93 | date_format: str, optional, 日期的格式, 默认'%Y-%m-%d' 94 | :return: pd.DataFrame 整理好的因子数据 95 | """ 96 | if isinstance(factor_name, list): 97 | kwargs = merge(kwargs, {'output_data_format': OutputFormat.MULTI_INDEX_DF}) 98 | factor_names = factor_name 99 | else: 100 | factor_names = [factor_name] 101 | 102 | ret = pd.DataFrame() 103 | for factor_name in factor_names: 104 | LOGGER.info('Loading factor data {0}'.format(factor_name)) 105 | factor_loader = FactorLoader(start_date=start_date, 106 | end_date=end_date, 107 | factor_name=factor_name, 108 | **kwargs) 109 | factor_data = factor_loader.load_data() 110 | LOGGER.info('factor data {0} is loaded '.format(factor_name)) 111 | ret = pd.concat([ret, factor_data], axis=1) 112 | if kwargs.get('reset_col_names'): 113 | ret.columns = factor_names 114 | if save_file: 115 | save_data_to_file(ret, save_file) 116 | LOGGER.critical('Data saved in {0}'.format(save_file)) 117 | return ret 118 | 119 | 120 | def factor_help(): 121 | """ 122 | :return: 返回定义的数据字典(简易版) 123 | """ 124 | LOGGER.info('Factors that are available to query') 125 | data_dict = WIND_QUERY_HELPER.data_dict 126 | print_table(data_dict['explanation'], name='Data_Dict') 127 | return 128 | 129 | 130 | def factor_details_help(): 131 | """ 132 | :return: 返回定义的数据字典(详细版) 133 | """ 134 | LOGGER.info('Factors(details) that are available to query') 135 | data_dict = WIND_QUERY_HELPER.data_dict 136 | print_table(data_dict, name='Data_Dict') 137 | return 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
Latest Releaselatest release
Python version
Build Statusbuild status
18 | 19 | 20 | # WindAdapter 21 | 22 | *WindAdapter*是一个从wind网络终端读取和整理因子数据的简单工具: 相比于直接使用wsd/wss等wind函数, *WindAdapter*根据预先定义好的参数字典(用户也可以自行扩展更新), 可以让用户更便捷的读取和整理数据 23 | 24 | 具体而言, *WindAdapter*的功能有 25 | 26 | - 根据用户输入因子名称和读取区间, 以及预定义的数据字典(如本项目默认的‘data_dict.csv’), *自动*拼接参数语句与接口函数, 从wind网络终端读取数据 27 | - 返回因子数据的格式为pandas.DataFrame 28 | 可选择MultiIndex(index为date和secID, value=因子值) 或者 PivotTable格式(index=date, col=secID,value=因子值) 29 | - 返回因子数据可在读取完毕后选择保存为csv或者pickle格式 30 | - 还可返回指数成分股列表: 可选择全市场或者某个指数 31 | - 读取市场的实时数据 32 | 33 | *Note* 34 | 35 | - 只有在数据字典中预定义好的因子才能利用*WindAdpater*读取,目前已整理好约20个因子的参数以及接口列表, 可使用*factor_help*首先进行查询 36 | - 用户可以在本地自行更新数据字典作为*WindAdpater*引用(方法见下文*reset_data_dict_path*)或者等待本项目后续更新 37 | 38 | 39 | ## Quick Start 40 | 41 | ##### get_universe 42 | 43 | ``` python 44 | # 读取2017年1月3日沪深300指数成分股(同时返回对应的权重如果output_weight=True) 45 | hs300_comp = get_universe('000300.SH', date='20170103', output_weight=True) 46 | ``` 47 | 48 | ##### factor_help 49 | 50 | ``` python 51 | from WindAdapter import factor_help 52 | 53 | factor_help() 54 | 55 | # 将会输出目前可以查询的因子名称列表 56 | 57 | ``` 58 | 59 | 60 | 61 | 62 | ##### factor_load 63 | ``` python 64 | from WindAdapter import factor_load 65 | 66 | # def factor_load(start_date, end_date, factor_name, save_file=None, **kwargs): 67 | """ 68 | :param start_date: str, 读取因子数据的开始日期 69 | :param end_date: str, 读取因子数据的结束日期 70 | :param factor_name: str, 因子名称,不区分大小写 71 | :param save_file: str, optional, 保存数据的文件名,可写成 '*.csv' 或者 '*.pkl' 72 | :param kwargs: dict, optional 73 | 74 | freq: str, optional, 因子数据的频率, 可选'M', 'W', 'S', 'Y', 参见enums.py - FreqType 75 | tenor: str, optional, 因子数据的周期, 对于截面数据(如换手率,收益率),需要给定数据区间(向前), 可选数字+FreqType, 如'3M' 76 | sec_id, str/list, optional, 股票代码或者是指数代码 77 | output_data_format: enum, optional, 参见enums.py - FreqType 78 | MULTI_INDEX_DF: multi-index DataFrame, index=[date, secID], value = factor 79 | PIVOT_TABLE_DF: DataFrame, index=date, columns = secID 80 | is_index: bool, optional, True: 输入的sec_id是指数,实际需要读取的是该指数成分股的因子数据, 81 | False: 直接读取sec_id的因子数据 82 | date_format: str, optional, 日期的格式, 默认'%Y-%m-%d' 83 | :return: pd.DataFrame 整理好的因子数据 84 | """ 85 | 86 | 87 | # 读取 2014年1月1日 至 1月15日 全部A股个股的日频行情数据,包括开高低收、复权因子、交易状态等,并保存成csv格式 88 | factor_load('2014-01-01', '2014-01-15', 'FULL_OHLC_DAY', sec_id='ashare', is_index=True, freq='D', save_file='ashare.csv') 89 | 90 | # 读取 2014年上半年 000001.SZ和000002.SZ的PB数据, 并保存成csv格式(默认数据频率为月频,数据格式为multi-index DataFrame) 91 | factor_load('2014-01-01', '2014-07-10', 'PB', sec_id=['000001.SZ', '000002.SZ'], is_index=False, save_file='PB.csv') 92 | 93 | # 读取2016年1月 全部A顾个股的每日收盘价,并保存成pickle格式 94 | factor_load('2014-01-01', '2014-07-10', 'close', sec_id='ashare', is_index=True, freq='D', save_file='close.pkl') 95 | 96 | # 读取沪深300成分股从2014年1月至3月,频率为每月(freq=M)的季度(tenor='3M')收益, 并保存成csv格式 97 | factor_load('2014-01-01', '2014-03-31', 'return', sec_id='000300.SH', is_index=True, freq='M', tenor='3M', save_file='HS300_return_1Q.csv')``` 98 | ``` 99 | 100 | *Note 1*: 返回的数据最近的日期等于入参中的end_date,前推的日期为根据频率(freq)和end_date往前推算的交易日 101 | 102 | *Note 2*: tenor取值需要符合x-utils包的要求,具体请参照其[帮助](https://github.com/iLampard/x-utils)中所举的例子 103 | 104 | 另外,指数成分股权重也是作为因子,从*factor_loader*读取 105 | 106 | ``` python 107 | # 读取指数成分股行业权重: 沪深300的申万一级行业权重分布 108 | # 由于申万一级行业于2014年2月进行了调整,而wind的行业代码不可回溯,故2014年2月前的指数成分股权重之和不等于1 109 | factor_load('2014-01-01', '2014-03-31', 'INDUSTRY_WEIGHT_C1', sec_id='000300.SH') 110 | 111 | 112 | 2014-12-31 801010.SI 0.52 113 | 801020.SI 2.79 114 | 801030.SI 2.37 115 | 801040.SI 1.42 116 | 801050.SI 3.28 117 | 801080.SI 1.56 118 | 801110.SI 2.80 119 | 801120.SI 4.23 120 | 801130.SI 0.32 121 | 801150.SI 4.71 122 | 801160.SI 4.06 123 | 801170.SI 2.89 124 | 801180.SI 5.08 125 | 801200.SI 1.98 126 | 801210.SI 0.21 127 | 801230.SI 0.45 128 | 801710.SI 0.73 129 | 801720.SI 4.66 130 | 801730.SI 1.74 131 | 801740.SI 2.19 132 | 801750.SI 2.09 133 | ... 134 | ``` 135 | 136 | factor_load还可以接受list of factor names 进行数据读取 137 | 138 | ``` python 139 | factor_load('2014-01-01', '2014-07-10', ['PB', 'MV'], sec_id=['000001.SZ', '000002.SZ'], is_index=False,reset_col_names=True) 140 | 141 | ``` 142 |
143 | 144 | ##### get_live 145 | 146 | 读取实时数据(通过wsq接口) 147 | 148 | 149 | ``` python 150 | # def get_live(sec_id, block_size=400): 151 | """ 152 | :param sec_id: list, wind股票代码,如果是全市场,可输入'fulla'或者'ashare' 153 | :param block_size: 内部调用wsq接口一次提取的数量,默认400支 154 | :return: pd.DataFrame, index=sec id, header = [rt_open,rt_high,rt_low,rt_last,rt_vol,rt_amt,rt_vol_ratio,rt_pct_chg_5min] 155 | """ 156 | 157 | ``` 158 | 159 | 如果和[Schedule](https://github.com/dbader/schedule)包结合,那么能方便连续读取wind的实时数据进行后续处理 160 | ``` python 161 | 162 | from WindAdapter import (get_universe, 163 | get_live) 164 | import schedule 165 | import time 166 | 167 | def live_contrib(universe): 168 | ret = get_live(universe) 169 | # blabblabal 170 | return 171 | 172 | universe = get_universe('ashare') 173 | schedule.every(1).minutes.do(live_contrib, universe) 174 | 175 | while True: 176 | schedule.run_pending() 177 | time.sleep(1) 178 | 179 | 180 | ``` 181 | 182 | 183 | 184 | 185 | 186 | 其他细节参见[WindAdapter tutorial](/example/tutorial.ipymd) 187 | 188 | 189 | ## 依赖 190 | ``` python 191 | numpy 192 | pandas 193 | python-decouple 194 | WindPy 195 | x-utils 196 | ``` 197 | 198 | ## 安装 199 | 200 | ``` python 201 | pip install WindAdapter 202 | ``` 203 | -------------------------------------------------------------------------------- /WindAdapter/tests/test_api.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import unittest 4 | from datetime import datetime 5 | import pandas as pd 6 | 7 | try: 8 | from unittest.mock import patch 9 | except ImportError: 10 | from mock import patch 11 | from pandas.util.testing import assert_frame_equal 12 | from WindAdapter.api import (factor_load, 13 | get_universe) 14 | from WindAdapter.helper import WindQueryHelper 15 | from WindAdapter.enums import OutputFormat 16 | 17 | wind_query_helper = WindQueryHelper() 18 | 19 | 20 | class MockWindData(object): 21 | def __init__(self, data, codes, error_code, fields, times): 22 | self.Data = data 23 | self.Codes = codes 24 | self.ErrorCode = error_code 25 | self.Fields = fields 26 | self.Times = times 27 | 28 | 29 | class TestApi(unittest.TestCase): 30 | @patch('WindAdapter.data_provider.WindDataProvider.biz_days_list') 31 | @patch('WindAdapter.data_provider.WindDataProvider.query_data') 32 | def test_factor_load_case1(self, mock_query_data, mock_days_list): 33 | """ 34 | 测试没有tenor的情况 35 | """ 36 | start_date = '2016-01-01' 37 | end_date = '2016-02-01' 38 | factor_name = 'PB' 39 | sec_id = ['000001.SZ', '000002.SZ', '000003.SZ'] 40 | 41 | mock_data = MockWindData(data=[[1, 3, 5]], 42 | codes=sec_id, 43 | error_code=0, 44 | fields=['PB'], 45 | times=[datetime(2016, 1, 1), 46 | datetime(2016, 2, 29)]) 47 | mock_query_data.return_value = mock_data 48 | mock_days_list.return_value = [datetime(2016, 1, 29), datetime(2016, 2, 29)] 49 | 50 | calculated = factor_load(start_date=start_date, 51 | end_date=end_date, 52 | factor_name=factor_name, 53 | sec_id=sec_id, 54 | output_data_format=OutputFormat.MULTI_INDEX_DF, 55 | is_index=False) 56 | 57 | expected = pd.DataFrame(data=[1, 3, 5, 1, 3, 5], 58 | index=pd.MultiIndex.from_product([['2016-01-29', '2016-02-29'], 59 | ['000001.SZ', '000002.SZ', '000003.SZ']], 60 | names=['date', 'secID']), 61 | columns=['factor']) 62 | assert_frame_equal(calculated, expected) 63 | 64 | calculated = factor_load(start_date=start_date, 65 | end_date=end_date, 66 | factor_name=factor_name, 67 | sec_id=sec_id, 68 | output_data_format=OutputFormat.PIVOT_TABLE_DF, 69 | is_index=False) 70 | expected = pd.DataFrame(data=[[1, 3, 5], [1, 3, 5]], 71 | columns=['000001.SZ', '000002.SZ', '000003.SZ'], 72 | index=['2016-01-29', '2016-02-29']) 73 | assert_frame_equal(calculated, expected) 74 | 75 | @patch('WindAdapter.data_provider.WindDataProvider.query_data') 76 | @patch('WindAdapter.data_provider.WindDataProvider.biz_days_list') 77 | @patch('WindAdapter.data_provider.WindDataProvider.forward_date') 78 | def test_factor_load_case2(self, mock_adv_date, mock_days_list, mock_query_data): 79 | """ 80 | 测试有tenor的情况 81 | """ 82 | start_date = '2016-01-01' 83 | end_date = '2016-02-01' 84 | factor_name = 'STDQ' 85 | sec_id = ['000001.SZ', '000002.SZ', '000003.SZ', '000004.SZ'] 86 | 87 | mock_data = MockWindData(data=[[1, 2, 3, 4]], 88 | codes=sec_id, 89 | error_code=0, 90 | fields=['STDQ'], 91 | times=[datetime(2016, 1, 1)]) 92 | mock_query_data.return_value = mock_data 93 | mock_days_list.return_value = [datetime(2016, 1, 1), datetime(2016, 2, 1)] 94 | mock_adv_date.return_value = '2015-09-01' 95 | 96 | calculated = factor_load(start_date=start_date, 97 | end_date=end_date, 98 | factor_name=factor_name, 99 | sec_id=sec_id, 100 | tenor='3M', 101 | output_data_format=OutputFormat.MULTI_INDEX_DF, 102 | is_index=False) 103 | expected = pd.DataFrame(data=[1, 2, 3, 4, 1, 2, 3, 4], 104 | index=pd.MultiIndex.from_product([['2016-01-01', '2016-02-01'], 105 | ['000001.SZ', '000002.SZ', '000003.SZ', 106 | '000004.SZ']], 107 | names=['date', 'secID']), 108 | columns=['factor']) 109 | assert_frame_equal(calculated, expected) 110 | 111 | calculated = factor_load(start_date=start_date, 112 | end_date=end_date, 113 | factor_name=factor_name, 114 | sec_id=sec_id, 115 | tenor='3M', 116 | output_data_format=OutputFormat.PIVOT_TABLE_DF, 117 | is_index=False) 118 | expected = pd.DataFrame(data=[[1, 2, 3, 4], [1, 2, 3, 4]], 119 | index=['2016-01-01', '2016-02-01'], 120 | columns=['000001.SZ', '000002.SZ', '000003.SZ', '000004.SZ']) 121 | assert_frame_equal(calculated, expected) 122 | 123 | @patch('WindAdapter.data_provider.WindDataProvider.get_universe') 124 | def test_get_universe(self, mock_get_universe): 125 | index_id = 'fullA' 126 | mock_get_universe.return_value = ['000001.SZ', '000002.SZ', '000003.SZ', 'other codes of fullA'] 127 | expected = ['000001.SZ', '000002.SZ', '000003.SZ', 'other codes of fullA'] 128 | calculated = get_universe(index_id) 129 | self.assertEqual(calculated, expected) 130 | 131 | index_id = '000905.SH' 132 | mock_get_universe.return_value = pd.DataFrame(data=[0.228, 0.238, 0.164], 133 | index=['000006.SZ', '000012.SZ', '000021.SZ'], 134 | columns=['weight']) 135 | expected = pd.DataFrame(data=[0.228, 0.238, 0.164], 136 | index=['000006.SZ', '000012.SZ', '000021.SZ'], 137 | columns=['weight']) 138 | calculated = get_universe(index_id, '2017-12-04', True) 139 | assert_frame_equal(calculated, expected) 140 | -------------------------------------------------------------------------------- /WindAdapter/tests/test_windpy.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import unittest 4 | 5 | try: 6 | from unittest.mock import patch 7 | except ImportError: 8 | from mock import patch 9 | 10 | try: 11 | from WindPy import w 12 | except ImportError: 13 | pass 14 | 15 | from WindAdapter.data_provider import WindDataProvider 16 | from WindAdapter.helper import WindQueryHelper 17 | from WindAdapter.factor_loader import FactorLoader 18 | from WindAdapter.enums import Header 19 | from datetime import (datetime, 20 | date) 21 | 22 | wind_query_helper = WindQueryHelper() 23 | wind_data_provider = WindDataProvider() 24 | 25 | """ 26 | 该文件用以测试WindPy接口数据结构是否与从前保持一致,以确保WindAdapter数据处理得以照常进行 27 | """ 28 | 29 | 30 | class WindData(object): 31 | def __init__(self, data, codes, error_code, fields, times): 32 | self.Data = data 33 | self.Codes = codes 34 | self.ErrorCode = error_code 35 | self.Fields = fields 36 | self.Times = times 37 | 38 | def __eq__(self, other): 39 | if (self.Data == other.Data 40 | and self.Codes == other.Codes 41 | and self.ErrorCode == other.ErrorCode 42 | and self.Fields == other.Fields and self.Times == other.Times): 43 | return True 44 | else: 45 | return False 46 | 47 | 48 | class TestDataProvider(unittest.TestCase): 49 | def test_forward_date(self): 50 | ref_date = '2017-12-04' 51 | tenor = ['1b', '2d', '3w', '4m', '5y'] 52 | expected = ['2017-12-04', '2017-12-05', '2017-11-14', '2017-08-07', '2012-12-05'] 53 | calculated = [WindDataProvider.forward_date(ref_date, tenor[i]) for i in range(len(tenor))] 54 | self.assertEqual(calculated, expected) 55 | 56 | ref_date = '20170101' 57 | tenor = ['1b', '2d', '3w', '4m', '5y'] 58 | expected = ['2017-01-03', '2017-01-03', '2016-12-13', '2016-09-02', '2012-01-05'] 59 | calculated = [WindDataProvider.forward_date(ref_date, tenor[i], date_format='%Y%m%d') for i in 60 | range(len(tenor))] 61 | self.assertEqual(calculated, expected) 62 | 63 | def test_query_data(self): 64 | # query_data(api, sec_id, indicator, extra_params=None, start_date=None, end_date=None) 65 | sec_id = ['000001.SZ', '000002.SZ'] 66 | start_date = '2017-01-03' 67 | end_date = '2017-01-04' 68 | 69 | # w.wsd && factor_name = 'PB' 70 | api = 'w.wsd' 71 | indicator = 'pb_lf' 72 | raw_data = wind_data_provider.query_data(api, sec_id, indicator, start_date=start_date, end_date=end_date) 73 | calculated = WindData(data=raw_data.Data, 74 | codes=raw_data.Codes, 75 | error_code=raw_data.ErrorCode, 76 | fields=raw_data.Fields, 77 | times=raw_data.Times) 78 | expected = WindData(data=[[0.8822379112243652, 0.8822379112243652], [2.279218912124634, 2.292412519454956]], 79 | codes=['000001.SZ', '000002.SZ'], 80 | error_code=0, 81 | fields=['PB_LF'], 82 | times=[date(2017, 1, 3), date(2017, 1, 4)]) 83 | self.assertEqual(calculated, expected) 84 | 85 | # w.wss && factor_name = 'RETURN' 86 | api = 'w.wss' 87 | factor_name = 'RETURN' 88 | indicator = 'pct_chg_per' 89 | factor_loader = FactorLoader(start_date, end_date, factor_name, sec_id=sec_id, is_index=False, tenor='3M') 90 | main_params, extra_params = wind_query_helper.get_query_params(factor_name) 91 | extra_params[Header.TENOR.value] = factor_loader._get_enum_value(factor_loader.tenor) \ 92 | if factor_loader.tenor is not None else None 93 | merged_extra_params = factor_loader._merge_query_params(extra_params, start_date) 94 | raw_data = wind_data_provider.query_data(api, sec_id, indicator, 95 | extra_params=merged_extra_params, 96 | start_date=start_date, end_date=start_date) 97 | calculated = WindData(data=raw_data.Data, 98 | codes=raw_data.Codes, 99 | error_code=raw_data.ErrorCode, 100 | fields=raw_data.Fields, 101 | times=len(raw_data.Times)) 102 | expected = WindData(data=[[0.43859649122806044, -20.177127454755485]], 103 | codes=['000001.SZ', '000002.SZ'], 104 | error_code=0, 105 | fields=['PCT_CHG_PER'], 106 | times=1) 107 | self.assertEqual(calculated, expected) 108 | 109 | # w.wsi && factor_name = 'OHLCV_MIN' 110 | api = 'w.wsi' 111 | indicator = 'open,high,low,close,volume' 112 | start_date = '2017-01-03 09:30:00' 113 | end_date = '2017-01-03 09:32:00' 114 | factor_name = 'OHLCV_MIN' 115 | factor_loader = FactorLoader(start_date, end_date, factor_name, sec_id=sec_id) 116 | main_params, extra_params = wind_query_helper.get_query_params(factor_name) 117 | merged_extra_params = factor_loader._merge_query_params(extra_params, start_date) 118 | raw_data = wind_data_provider.query_data(api, sec_id, indicator, extra_params=merged_extra_params, 119 | start_date=start_date, end_date=end_date) 120 | calculated = WindData(data=raw_data.Data, 121 | codes=raw_data.Codes, 122 | error_code=raw_data.ErrorCode, 123 | fields=raw_data.Fields, 124 | times=raw_data.Times) 125 | expected = WindData(data=[[datetime(2017, 1, 3, 9, 30), datetime(2017, 1, 3, 9, 31), 126 | datetime(2017, 1, 3, 9, 30), datetime(2017, 1, 3, 9, 31)], 127 | ['000001.SZ', '000001.SZ', '000002.SZ', '000002.SZ'], 128 | [8.977128569075722, 8.967274421359942, 19.87384420457807, 19.951211967904893], 129 | [8.977128569075722, 8.977128569075722, 19.970553908736598, 19.970553908736598], 130 | [8.967274421359942, 8.967274421359942, 19.87384420457807, 19.922199056657337], 131 | [8.967274421359942, 8.967274421359942, 19.951211967904893, 19.970553908736598], 132 | [673660L, 433800L, 119900L, 146700L]], 133 | codes=['MultiCodes'], 134 | error_code=0, 135 | fields=['time', 'windcode', 'open', 'high', 'low', 'close', 'volume'], 136 | times=[datetime(2017, 1, 3, 9, 30), datetime(2017, 1, 3, 9, 31), 137 | datetime(2017, 1, 3, 9, 30), datetime(2017, 1, 3, 9, 31)]) 138 | self.assertEqual(calculated, expected) 139 | 140 | # # w.wsq && factor_name = 'LIVE' 141 | api = 'w.wsq' 142 | indicator = 'rt_open,rt_high,rt_low,rt_last,rt_vol,rt_amt,rt_vol_ratio,rt_pct_chg_5min' 143 | raw_data = wind_data_provider.query_data(api, sec_id, indicator) 144 | calculated = WindData(data=len(raw_data.Data), 145 | codes=raw_data.Codes, 146 | error_code=raw_data.ErrorCode, 147 | fields=raw_data.Fields, 148 | times=len(raw_data.Times)) 149 | expected = WindData(data=8, 150 | codes=['000001.SZ', '000002.SZ'], 151 | error_code=0, 152 | fields=['RT_OPEN', 'RT_HIGH', 'RT_LOW', 'RT_LAST', 'RT_VOL', 153 | 'RT_AMT', 'RT_VOL_RATIO', 'RT_PCT_CHG_5MIN'], 154 | times=1) 155 | self.assertEqual(calculated, expected) 156 | 157 | # # w.wset && factor_name = 'INDUSTRY_WEIGHT_C1' 158 | api = 'w.wset' 159 | index_id = '000300.SH' 160 | short_params = 'windcode=' + index_id 161 | params = short_params if start_date is None else short_params + ';date=' + str(start_date) 162 | raw_data = w.wset('IndexConstituent', params) 163 | calculated = WindData(data=len(raw_data.Data), 164 | codes=len(raw_data.Codes), 165 | error_code=raw_data.ErrorCode, 166 | fields=raw_data.Fields, 167 | times=len(raw_data.Times)) 168 | expected = WindData(data=4, 169 | codes=300, 170 | error_code=0, 171 | fields=['date', 'wind_code', 'sec_name', 'i_weight'], 172 | times=1) 173 | self.assertEqual(calculated, expected) 174 | 175 | raw_data = w.wset('IndexConstituent', short_params) 176 | calculated = WindData(data=len(raw_data.Data), 177 | codes=len(raw_data.Codes), 178 | error_code=raw_data.ErrorCode, 179 | fields=raw_data.Fields, 180 | times=len(raw_data.Times)) 181 | expected = WindData(data=4, 182 | codes=300, 183 | error_code=0, 184 | fields=['date', 'wind_code', 'sec_name', 'i_weight'], 185 | times=1) 186 | self.assertEqual(calculated, expected) 187 | -------------------------------------------------------------------------------- /WindAdapter/factor_loader.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import re 4 | 5 | import pandas as pd 6 | from argcheck import expect_types 7 | import numpy as np 8 | from WindAdapter.data_provider import WindDataProvider 9 | from WindAdapter.enums import FreqType 10 | from WindAdapter.enums import Header 11 | from WindAdapter.enums import OutputFormat 12 | from WindAdapter.helper import WindQueryHelper 13 | from WindAdapter.utils import date_convert_2_str 14 | from WindAdapter.utils import py_assert 15 | 16 | WIND_QUERY_HELPER = WindQueryHelper() 17 | WIND_DATA_PROVIDER = WindDataProvider() 18 | 19 | 20 | class FactorLoader: 21 | def __init__(self, start_date, end_date, factor_name, **kwargs): 22 | self.start_date = start_date 23 | self.end_date = end_date 24 | self.factor_name = factor_name 25 | self.sec_id = kwargs.get('sec_id', 'fulla') 26 | self.freq = kwargs.get('freq', FreqType.EOM) 27 | self.tenor = kwargs.get('tenor', None) 28 | self.output_data_format = kwargs.get('output_data_format', OutputFormat.MULTI_INDEX_DF) 29 | self.is_index = kwargs.get('is_index', True) 30 | self.date_format = kwargs.get('date_format', '%Y-%m-%d') 31 | self.block_size = kwargs.get('block_size', 400) 32 | 33 | @staticmethod 34 | def _check_industry_params(factor_name): 35 | if factor_name[:-1] == 'INDUSTRY_WEIGHT_C' or factor_name[:-1] == 'sw_c' or factor_name[:-1] == 'sw_name_c': 36 | return ';industryType=' + str(filter(str.isdigit, str(factor_name))) 37 | else: 38 | return '' 39 | 40 | def _merge_query_params(self, params, date=None): 41 | ret = '' 42 | for key, value in params.iteritems(): 43 | if key == 'tenor' and pd.isnull(value): 44 | ret += 'tradeDate=' + date + ';' 45 | elif not pd.isnull(value): 46 | if key == Header.TENOR: 47 | py_assert(date is not None, ValueError, 'date must be given if tenor is not None') 48 | # unit = ''.join(re.findall('[0-9]+', params[Header.TENOR])) 49 | # freq = FreqType(params[Header.TENOR][len(unit):]) 50 | ret += 'startDate=' + WIND_DATA_PROVIDER.forward_date(date, value, 51 | self.date_format) + ';endDate=' + date + ';' 52 | elif key == Header.FREQ and value[:3] == 'min': 53 | ret += ('BarSize=' + value[3:] + ';') 54 | else: 55 | ret += (key + '=' + str(value) + ';') 56 | ret = ret[:-1] + FactorLoader._check_industry_params(params.name) 57 | return ret 58 | 59 | @staticmethod 60 | @expect_types(enum_var=(FreqType, str)) 61 | def _get_enum_value(enum_var): 62 | if isinstance(enum_var, FreqType): 63 | return enum_var.value 64 | elif isinstance(enum_var, str): 65 | return enum_var 66 | 67 | def _get_sec_id(self, date): 68 | if isinstance(self.sec_id, str): 69 | sec_id = WIND_DATA_PROVIDER.get_universe(self.sec_id, date=date) \ 70 | if self.is_index else self.sec_id 71 | elif isinstance(self.sec_id, list): 72 | sec_id = self.sec_id 73 | else: 74 | raise TypeError('FactorLoader._get_sec_id: sec_id must be either list or string') 75 | 76 | return sec_id 77 | 78 | def _retrieve_data(self, main_params, extra_params, output_data_format): 79 | output_data = pd.DataFrame() 80 | api = main_params[Header.API] 81 | 82 | if api == 'w.wsq': 83 | loop_times = int(len(self.sec_id) / self.block_size) + 1 84 | for j in range(loop_times): 85 | code_set = self.sec_id[j * self.block_size: (j + 1) * self.block_size] 86 | raw_data = WIND_DATA_PROVIDER.query_data(api=api, 87 | sec_id=code_set, 88 | indicator=main_params[Header.INDICATOR]) 89 | length = len(raw_data.Data[0]) 90 | output_data = pd.concat( 91 | [output_data, pd.DataFrame(np.concatenate(([raw_data.Times * length], raw_data.Data))).T], axis=0) 92 | output_data.columns = ['date'] + [field[3:] for field in main_params[Header.INDICATOR].split(',')] 93 | elif api == 'w.wsi': 94 | merged_extra_params = self._merge_query_params(extra_params, date=self.end_date) 95 | raw_data = WIND_DATA_PROVIDER.query_data(api=api, 96 | sec_id=self.sec_id, 97 | indicator=main_params[Header.INDICATOR], 98 | extra_params=merged_extra_params, 99 | start_date=self.start_date, 100 | end_date=self.end_date) 101 | multi_factors = True if extra_params[Header.MULTIFACTORS] == 'Y' else False 102 | output_data = WIND_QUERY_HELPER.reformat_wind_data(raw_data=raw_data, 103 | date=self.end_date, 104 | multi_factors=multi_factors) 105 | else: 106 | dates = WIND_DATA_PROVIDER.biz_days_list(start_date=self.start_date, 107 | end_date=self.end_date, 108 | freq=self.freq) 109 | for fetch_date in dates: 110 | if not pd.isnull(extra_params[Header.REPORTADJ]): 111 | date = WIND_QUERY_HELPER.latest_report_date(fetch_date) 112 | else: 113 | date = fetch_date 114 | date = date_convert_2_str(date) 115 | 116 | sec_id = WIND_DATA_PROVIDER.get_universe(self.sec_id, date=date) \ 117 | if self.is_index else self.sec_id 118 | if api == 'w.wsd': 119 | merged_extra_params = self._merge_query_params(extra_params, date=date) 120 | raw_data = WIND_DATA_PROVIDER.query_data(api=api, 121 | sec_id=sec_id, 122 | indicator=main_params[Header.INDICATOR], 123 | extra_params=merged_extra_params, 124 | start_date=date, 125 | end_date=date) 126 | elif api == 'w.wss': 127 | # py_assert(not pd.isnull(extra_params[Header.TENOR]), ValueError, 128 | # 'tenor must be given for query factor {0}'.format(self.factor_name)) 129 | merged_extra_params = self._merge_query_params(extra_params, date=date) 130 | raw_data = WIND_DATA_PROVIDER.query_data(api=api, 131 | sec_id=sec_id, 132 | indicator=main_params[Header.INDICATOR], 133 | extra_params=merged_extra_params) 134 | else: 135 | raise ValueError('FactorLoader._retrieve_data: unacceptable value of parameter api') 136 | 137 | multi_factors = True if extra_params[Header.MULTIFACTORS] == 'Y' else False 138 | tmp = WIND_QUERY_HELPER.reformat_wind_data(raw_data=raw_data, 139 | date=fetch_date, 140 | output_data_format=output_data_format, 141 | multi_factors=multi_factors) 142 | output_data = pd.concat([output_data, tmp], axis=0) 143 | 144 | return output_data 145 | 146 | def _load_single_factor(self): 147 | main_params, extra_params = WIND_QUERY_HELPER.get_query_params(self.factor_name) 148 | extra_params[Header.TENOR.value] = self._get_enum_value(self.tenor) if self.tenor is not None else None 149 | extra_params[Header.FREQ.value] = self._get_enum_value(self.freq) 150 | ret = self._retrieve_data(main_params=main_params, 151 | extra_params=extra_params, 152 | output_data_format=self.output_data_format) 153 | return ret 154 | 155 | def load_data(self): 156 | if self.factor_name[:-3] == 'INDUSTRY_WEIGHT': 157 | ret = self._load_industry_weight() 158 | else: 159 | ret = self._load_single_factor() 160 | return ret 161 | 162 | def _load_industry_weight(self): 163 | ret = pd.DataFrame() 164 | dates = WIND_DATA_PROVIDER.biz_days_list(start_date=self.start_date, 165 | end_date=self.end_date, 166 | freq=self.freq) 167 | extra_params = self._check_industry_params(self.factor_name) 168 | for date in dates: 169 | date = date_convert_2_str(date) 170 | index_info = WIND_DATA_PROVIDER.get_universe(self.sec_id, date=date, output_weight=True) 171 | class_info = WIND_DATA_PROVIDER.query_data(api='w.wsd', 172 | # sec_id=index_info[1], 173 | sec_id=index_info.index.tolist(), 174 | indicator='indexcode_sw', 175 | extra_params=extra_params, 176 | start_date=date, 177 | end_date=date) 178 | 179 | industry_weight = pd.DataFrame(data={'sec_id': index_info.index, 180 | 'class_id': class_info.Data[0], 181 | 'sec_weight': index_info['weight']}, 182 | index=index_info.index) 183 | 184 | tmp = industry_weight.groupby('class_id').sum().T 185 | tmp.index = [date] 186 | tmp = WIND_QUERY_HELPER.convert_2_multi_index(tmp) \ 187 | if self.output_data_format == OutputFormat.MULTI_INDEX_DF else tmp 188 | ret = ret.append(tmp) 189 | return ret 190 | -------------------------------------------------------------------------------- /example/tutorial.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "name": "stdout", 10 | "output_type": "stream", 11 | "text": [ 12 | "[2017-06-05 15:18:16] - WindAdapter - CRITICAL - Exception in function get_universe -- get_universe() got an unexpected keyword argument 'output_weight'\n" 13 | ] 14 | }, 15 | { 16 | "name": "stdout", 17 | "output_type": "stream", 18 | "text": [ 19 | "None\n" 20 | ] 21 | } 22 | ], 23 | "source": [ 24 | "from WindAdapter import get_universe\n", 25 | "\n", 26 | "# 读取指数成分股\n", 27 | "hs300_comp = get_universe('000300.SH', date='20170103', output_weight=True)\n", 28 | "print hs300_comp" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": 1, 34 | "metadata": { 35 | "collapsed": false 36 | }, 37 | "outputs": [ 38 | { 39 | "name": "stdout", 40 | "output_type": "stream", 41 | "text": [ 42 | "Welcome to use Wind Quant API for Python (WindPy)!\nYou can use w.menu to help yourself to create commands(WSD,WSS,WST,WSI,WSQ,...)!\n\nCOPYRIGHT (C) 2016 WIND HONGHUI INFORMATION & TECHKNOLEWDGE CO., LTD. ALL RIGHTS RESERVED.\nIN NO CIRCUMSTANCE SHALL WIND BE RESPONSIBLE FOR ANY DAMAGES OR LOSSES CAUSED BY USING WIND QUANT API FOR Python.\n[2017-05-24 08:32:34] - WindAdapter - INFO - Factors that are available to query\n" 43 | ] 44 | }, 45 | { 46 | "data": { 47 | "text/html": [ 48 | "
\n", 49 | "\n", 50 | " \n", 51 | " \n", 52 | " \n", 53 | " \n", 54 | " \n", 55 | " \n", 56 | " \n", 57 | " \n", 58 | " \n", 59 | " \n", 60 | " \n", 61 | " \n", 62 | " \n", 63 | " \n", 64 | " \n", 65 | " \n", 66 | " \n", 67 | " \n", 68 | " \n", 69 | " \n", 70 | " \n", 71 | " \n", 72 | " \n", 73 | " \n", 74 | " \n", 75 | " \n", 76 | " \n", 77 | " \n", 78 | " \n", 79 | " \n", 80 | " \n", 81 | " \n", 82 | " \n", 83 | " \n", 84 | " \n", 85 | " \n", 86 | " \n", 87 | " \n", 88 | " \n", 89 | " \n", 90 | " \n", 91 | " \n", 92 | " \n", 93 | " \n", 94 | " \n", 95 | " \n", 96 | " \n", 97 | " \n", 98 | " \n", 99 | " \n", 100 | " \n", 101 | " \n", 102 | " \n", 103 | " \n", 104 | " \n", 105 | " \n", 106 | " \n", 107 | " \n", 108 | " \n", 109 | " \n", 110 | " \n", 111 | " \n", 112 | " \n", 113 | " \n", 114 | " \n", 115 | " \n", 116 | " \n", 117 | " \n", 118 | " \n", 119 | " \n", 120 | " \n", 121 | " \n", 122 | " \n", 123 | " \n", 124 | " \n", 125 | " \n", 126 | " \n", 127 | " \n", 128 | " \n", 129 | " \n", 130 | " \n", 131 | " \n", 132 | " \n", 133 | " \n", 134 | " \n", 135 | " \n", 136 | " \n", 137 | " \n", 138 | " \n", 139 | " \n", 140 | " \n", 141 | " \n", 142 | " \n", 143 | " \n", 144 | " \n", 145 | " \n", 146 | "
Data_Dictexplanation
name
MV总市值(不可回测)
PB市净率PB(LF)
STDQ区间换手率(基准 自由流通股本)
EquityGrowth_YoY净资产(同比增长率)
ROE净资产收益率(平均)
ProfitGrowth_Qr_YoY单季度 净利润同比增长率
TO_adj区间日均换手率(基准 自由流通股本)
RETURN区间涨跌幅
GrossProfit毛利
EP扣除非经常性损益后的净利润(TTM)
SP营业总收入(TTM)
OHLCV开盘价、最高价、最低价、收盘价、成交量
OPEN开盘价
HIGH最高价
LOW最低价
CLOSE收盘价
VOLUME成交量
SW_C1股票所属申万一级行业代码
SW_C2股票所属申万二级行业代码
INDUSTRY_WEIGHT_C1申万一级行业所占指数权重
INDUSTRY_WEIGHT_C2申万二级行业所占指数权重
\n", 147 | "
" 148 | ], 149 | "text/plain": [ 150 | "
\n", 151 | "\n", 152 | " \n", 153 | " \n", 154 | " \n", 155 | " \n", 156 | " \n", 157 | " \n", 158 | " \n", 159 | " \n", 160 | " \n", 161 | " \n", 162 | " \n", 163 | " \n", 164 | " \n", 165 | " \n", 166 | " \n", 167 | " \n", 168 | " \n", 169 | " \n", 170 | " \n", 171 | " \n", 172 | " \n", 173 | " \n", 174 | " \n", 175 | " \n", 176 | " \n", 177 | " \n", 178 | " \n", 179 | " \n", 180 | " \n", 181 | " \n", 182 | " \n", 183 | " \n", 184 | " \n", 185 | " \n", 186 | " \n", 187 | " \n", 188 | " \n", 189 | " \n", 190 | " \n", 191 | " \n", 192 | " \n", 193 | " \n", 194 | " \n", 195 | " \n", 196 | " \n", 197 | " \n", 198 | " \n", 199 | " \n", 200 | " \n", 201 | " \n", 202 | " \n", 203 | " \n", 204 | " \n", 205 | " \n", 206 | " \n", 207 | " \n", 208 | " \n", 209 | " \n", 210 | " \n", 211 | " \n", 212 | " \n", 213 | " \n", 214 | " \n", 215 | " \n", 216 | " \n", 217 | " \n", 218 | " \n", 219 | " \n", 220 | " \n", 221 | " \n", 222 | " \n", 223 | " \n", 224 | " \n", 225 | " \n", 226 | " \n", 227 | " \n", 228 | " \n", 229 | " \n", 230 | " \n", 231 | " \n", 232 | " \n", 233 | " \n", 234 | " \n", 235 | " \n", 236 | " \n", 237 | " \n", 238 | " \n", 239 | " \n", 240 | " \n", 241 | " \n", 242 | " \n", 243 | " \n", 244 | " \n", 245 | " \n", 246 | " \n", 247 | " \n", 248 | "
Data_Dictexplanation
name
MV总市值(不可回测)
PB市净率PB(LF)
STDQ区间换手率(基准 自由流通股本)
EquityGrowth_YoY净资产(同比增长率)
ROE净资产收益率(平均)
ProfitGrowth_Qr_YoY单季度 净利润同比增长率
TO_adj区间日均换手率(基准 自由流通股本)
RETURN区间涨跌幅
GrossProfit毛利
EP扣除非经常性损益后的净利润(TTM)
SP营业总收入(TTM)
OHLCV开盘价、最高价、最低价、收盘价、成交量
OPEN开盘价
HIGH最高价
LOW最低价
CLOSE收盘价
VOLUME成交量
SW_C1股票所属申万一级行业代码
SW_C2股票所属申万二级行业代码
INDUSTRY_WEIGHT_C1申万一级行业所占指数权重
INDUSTRY_WEIGHT_C2申万二级行业所占指数权重
\n", 249 | "
" 250 | ] 251 | }, 252 | "execution_count": 0, 253 | "metadata": {}, 254 | "output_type": "execute_result" 255 | }, 256 | { 257 | "name": "stdout", 258 | "output_type": "stream", 259 | "text": [ 260 | "[2017-05-24 08:32:34] - WindAdapter - INFO - Factors(details) that are available to query\n" 261 | ] 262 | }, 263 | { 264 | "data": { 265 | "text/html": [ 266 | "
\n", 267 | "\n", 268 | " \n", 269 | " \n", 270 | " \n", 271 | " \n", 272 | " \n", 273 | " \n", 274 | " \n", 275 | " \n", 276 | " \n", 277 | " \n", 278 | " \n", 279 | " \n", 280 | " \n", 281 | " \n", 282 | " \n", 283 | " \n", 284 | " \n", 285 | " \n", 286 | " \n", 287 | " \n", 288 | " \n", 289 | " \n", 290 | " \n", 291 | " \n", 292 | " \n", 293 | " \n", 294 | " \n", 295 | " \n", 296 | " \n", 297 | " \n", 298 | " \n", 299 | " \n", 300 | " \n", 301 | " \n", 302 | " \n", 303 | " \n", 304 | " \n", 305 | " \n", 306 | " \n", 307 | " \n", 308 | " \n", 309 | " \n", 310 | " \n", 311 | " \n", 312 | " \n", 313 | " \n", 314 | " \n", 315 | " \n", 316 | " \n", 317 | " \n", 318 | " \n", 319 | " \n", 320 | " \n", 321 | " \n", 322 | " \n", 323 | " \n", 324 | " \n", 325 | " \n", 326 | " \n", 327 | " \n", 328 | " \n", 329 | " \n", 330 | " \n", 331 | " \n", 332 | " \n", 333 | " \n", 334 | " \n", 335 | " \n", 336 | " \n", 337 | " \n", 338 | " \n", 339 | " \n", 340 | " \n", 341 | " \n", 342 | " \n", 343 | " \n", 344 | " \n", 345 | " \n", 346 | " \n", 347 | " \n", 348 | " \n", 349 | " \n", 350 | " \n", 351 | " \n", 352 | " \n", 353 | " \n", 354 | " \n", 355 | " \n", 356 | " \n", 357 | " \n", 358 | " \n", 359 | " \n", 360 | " \n", 361 | " \n", 362 | " \n", 363 | " \n", 364 | " \n", 365 | " \n", 366 | " \n", 367 | " \n", 368 | " \n", 369 | " \n", 370 | " \n", 371 | " \n", 372 | " \n", 373 | " \n", 374 | " \n", 375 | " \n", 376 | " \n", 377 | " \n", 378 | " \n", 379 | " \n", 380 | " \n", 381 | " \n", 382 | " \n", 383 | " \n", 384 | " \n", 385 | " \n", 386 | " \n", 387 | " \n", 388 | " \n", 389 | " \n", 390 | " \n", 391 | " \n", 392 | " \n", 393 | " \n", 394 | " \n", 395 | " \n", 396 | " \n", 397 | " \n", 398 | " \n", 399 | " \n", 400 | " \n", 401 | " \n", 402 | " \n", 403 | " \n", 404 | " \n", 405 | " \n", 406 | " \n", 407 | " \n", 408 | " \n", 409 | " \n", 410 | " \n", 411 | " \n", 412 | " \n", 413 | " \n", 414 | " \n", 415 | " \n", 416 | " \n", 417 | " \n", 418 | " \n", 419 | " \n", 420 | " \n", 421 | " \n", 422 | " \n", 423 | " \n", 424 | " \n", 425 | " \n", 426 | " \n", 427 | " \n", 428 | " \n", 429 | " \n", 430 | " \n", 431 | " \n", 432 | " \n", 433 | " \n", 434 | " \n", 435 | " \n", 436 | " \n", 437 | " \n", 438 | " \n", 439 | " \n", 440 | " \n", 441 | " \n", 442 | " \n", 443 | " \n", 444 | " \n", 445 | " \n", 446 | " \n", 447 | " \n", 448 | " \n", 449 | " \n", 450 | " \n", 451 | " \n", 452 | " \n", 453 | " \n", 454 | " \n", 455 | " \n", 456 | " \n", 457 | " \n", 458 | " \n", 459 | " \n", 460 | " \n", 461 | " \n", 462 | " \n", 463 | " \n", 464 | " \n", 465 | " \n", 466 | " \n", 467 | " \n", 468 | " \n", 469 | " \n", 470 | " \n", 471 | " \n", 472 | " \n", 473 | " \n", 474 | " \n", 475 | " \n", 476 | " \n", 477 | " \n", 478 | " \n", 479 | "
Data_Dictapiindicatorpriceadjunitexplanationtype
name
MVwsdmkt_capF1.0总市值(不可回测)规模
PBwsdpb_lfFNaN市净率PB(LF)价值
STDQwssturn_free_perNaNNaN区间换手率(基准 自由流通股本)流动性
EquityGrowth_YoYwsdyoy_equityNaNNaN净资产(同比增长率)成长
ROEwsdroe_avgNaNNaN净资产收益率(平均)盈利
ProfitGrowth_Qr_YoYwsdqfa_yoyprofitNaNNaN单季度 净利润同比增长率盈利
TO_adjwssavg_turn_free_perNaNNaN区间日均换手率(基准 自由流通股本)流动性
RETURNwsspct_chg_perNaNNaN区间涨跌幅估值
GrossProfitwsdgrossmarginNaN100000000.0毛利盈利
EPwsddeductedprofit_ttmNaN100000000.0扣除非经常性损益后的净利润(TTM)盈利
SPwsdgr_ttmNaN100000000.0营业总收入(TTM)盈利
OHLCVwsdopen,high,low,close,volumeNaNNaN开盘价、最高价、最低价、收盘价、成交量技术
OPENwsdopenFNaN开盘价技术
HIGHwsdhighFNaN最高价技术
LOWwsdlowFNaN最低价技术
CLOSEwsdcloseFNaN收盘价技术
VOLUMEwsdvolumeFNaN成交量技术
SW_C1wsdindexcode_swNaNNaN股票所属申万一级行业代码基本信息
SW_C2wsdindexcode_swNaNNaN股票所属申万二级行业代码基本信息
INDUSTRY_WEIGHT_C1NaNNaNNaNNaN申万一级行业所占指数权重基本信息
INDUSTRY_WEIGHT_C2NaNNaNNaNNaN申万二级行业所占指数权重基本信息
\n", 480 | "
" 481 | ], 482 | "text/plain": [ 483 | "
\n", 484 | "\n", 485 | " \n", 486 | " \n", 487 | " \n", 488 | " \n", 489 | " \n", 490 | " \n", 491 | " \n", 492 | " \n", 493 | " \n", 494 | " \n", 495 | " \n", 496 | " \n", 497 | " \n", 498 | " \n", 499 | " \n", 500 | " \n", 501 | " \n", 502 | " \n", 503 | " \n", 504 | " \n", 505 | " \n", 506 | " \n", 507 | " \n", 508 | " \n", 509 | " \n", 510 | " \n", 511 | " \n", 512 | " \n", 513 | " \n", 514 | " \n", 515 | " \n", 516 | " \n", 517 | " \n", 518 | " \n", 519 | " \n", 520 | " \n", 521 | " \n", 522 | " \n", 523 | " \n", 524 | " \n", 525 | " \n", 526 | " \n", 527 | " \n", 528 | " \n", 529 | " \n", 530 | " \n", 531 | " \n", 532 | " \n", 533 | " \n", 534 | " \n", 535 | " \n", 536 | " \n", 537 | " \n", 538 | " \n", 539 | " \n", 540 | " \n", 541 | " \n", 542 | " \n", 543 | " \n", 544 | " \n", 545 | " \n", 546 | " \n", 547 | " \n", 548 | " \n", 549 | " \n", 550 | " \n", 551 | " \n", 552 | " \n", 553 | " \n", 554 | " \n", 555 | " \n", 556 | " \n", 557 | " \n", 558 | " \n", 559 | " \n", 560 | " \n", 561 | " \n", 562 | " \n", 563 | " \n", 564 | " \n", 565 | " \n", 566 | " \n", 567 | " \n", 568 | " \n", 569 | " \n", 570 | " \n", 571 | " \n", 572 | " \n", 573 | " \n", 574 | " \n", 575 | " \n", 576 | " \n", 577 | " \n", 578 | " \n", 579 | " \n", 580 | " \n", 581 | " \n", 582 | " \n", 583 | " \n", 584 | " \n", 585 | " \n", 586 | " \n", 587 | " \n", 588 | " \n", 589 | " \n", 590 | " \n", 591 | " \n", 592 | " \n", 593 | " \n", 594 | " \n", 595 | " \n", 596 | " \n", 597 | " \n", 598 | " \n", 599 | " \n", 600 | " \n", 601 | " \n", 602 | " \n", 603 | " \n", 604 | " \n", 605 | " \n", 606 | " \n", 607 | " \n", 608 | " \n", 609 | " \n", 610 | " \n", 611 | " \n", 612 | " \n", 613 | " \n", 614 | " \n", 615 | " \n", 616 | " \n", 617 | " \n", 618 | " \n", 619 | " \n", 620 | " \n", 621 | " \n", 622 | " \n", 623 | " \n", 624 | " \n", 625 | " \n", 626 | " \n", 627 | " \n", 628 | " \n", 629 | " \n", 630 | " \n", 631 | " \n", 632 | " \n", 633 | " \n", 634 | " \n", 635 | " \n", 636 | " \n", 637 | " \n", 638 | " \n", 639 | " \n", 640 | " \n", 641 | " \n", 642 | " \n", 643 | " \n", 644 | " \n", 645 | " \n", 646 | " \n", 647 | " \n", 648 | " \n", 649 | " \n", 650 | " \n", 651 | " \n", 652 | " \n", 653 | " \n", 654 | " \n", 655 | " \n", 656 | " \n", 657 | " \n", 658 | " \n", 659 | " \n", 660 | " \n", 661 | " \n", 662 | " \n", 663 | " \n", 664 | " \n", 665 | " \n", 666 | " \n", 667 | " \n", 668 | " \n", 669 | " \n", 670 | " \n", 671 | " \n", 672 | " \n", 673 | " \n", 674 | " \n", 675 | " \n", 676 | " \n", 677 | " \n", 678 | " \n", 679 | " \n", 680 | " \n", 681 | " \n", 682 | " \n", 683 | " \n", 684 | " \n", 685 | " \n", 686 | " \n", 687 | " \n", 688 | " \n", 689 | " \n", 690 | " \n", 691 | " \n", 692 | " \n", 693 | " \n", 694 | " \n", 695 | " \n", 696 | "
Data_Dictapiindicatorpriceadjunitexplanationtype
name
MVwsdmkt_capF1.0总市值(不可回测)规模
PBwsdpb_lfFNaN市净率PB(LF)价值
STDQwssturn_free_perNaNNaN区间换手率(基准 自由流通股本)流动性
EquityGrowth_YoYwsdyoy_equityNaNNaN净资产(同比增长率)成长
ROEwsdroe_avgNaNNaN净资产收益率(平均)盈利
ProfitGrowth_Qr_YoYwsdqfa_yoyprofitNaNNaN单季度 净利润同比增长率盈利
TO_adjwssavg_turn_free_perNaNNaN区间日均换手率(基准 自由流通股本)流动性
RETURNwsspct_chg_perNaNNaN区间涨跌幅估值
GrossProfitwsdgrossmarginNaN100000000.0毛利盈利
EPwsddeductedprofit_ttmNaN100000000.0扣除非经常性损益后的净利润(TTM)盈利
SPwsdgr_ttmNaN100000000.0营业总收入(TTM)盈利
OHLCVwsdopen,high,low,close,volumeNaNNaN开盘价、最高价、最低价、收盘价、成交量技术
OPENwsdopenFNaN开盘价技术
HIGHwsdhighFNaN最高价技术
LOWwsdlowFNaN最低价技术
CLOSEwsdcloseFNaN收盘价技术
VOLUMEwsdvolumeFNaN成交量技术
SW_C1wsdindexcode_swNaNNaN股票所属申万一级行业代码基本信息
SW_C2wsdindexcode_swNaNNaN股票所属申万二级行业代码基本信息
INDUSTRY_WEIGHT_C1NaNNaNNaNNaN申万一级行业所占指数权重基本信息
INDUSTRY_WEIGHT_C2NaNNaNNaNNaN申万二级行业所占指数权重基本信息
\n", 697 | "
" 698 | ] 699 | }, 700 | "execution_count": 0, 701 | "metadata": {}, 702 | "output_type": "execute_result" 703 | } 704 | ], 705 | "source": [ 706 | "from WindAdapter import factor_help, factor_details_help\n", 707 | "\n", 708 | "factor_help()\n", 709 | "factor_details_help()" 710 | ] 711 | }, 712 | { 713 | "cell_type": "code", 714 | "execution_count": 6, 715 | "metadata": {}, 716 | "outputs": [ 717 | { 718 | "name": "stdout", 719 | "output_type": "stream", 720 | "text": [ 721 | "[2017-05-24 08:40:17] - WindAdapter - INFO - Loading factor data INDUSTRY_WEIGHT_C1\n" 722 | ] 723 | }, 724 | { 725 | "name": "stdout", 726 | "output_type": "stream", 727 | "text": [ 728 | "[2017-05-24 08:40:30] - WindAdapter - INFO - factor data INDUSTRY_WEIGHT_C1 is loaded \n" 729 | ] 730 | }, 731 | { 732 | "name": "stdout", 733 | "output_type": "stream", 734 | "text": [ 735 | "[2017-05-24 08:40:30] - WindAdapter - CRITICAL - Data saved in 300.csv\n" 736 | ] 737 | }, 738 | { 739 | "data": { 740 | "text/html": [ 741 | "
\n", 742 | "\n", 743 | " \n", 744 | " \n", 745 | " \n", 746 | " \n", 747 | " \n", 748 | " \n", 749 | " \n", 750 | " \n", 751 | " \n", 752 | " \n", 753 | " \n", 754 | " \n", 755 | " \n", 756 | " \n", 757 | " \n", 758 | " \n", 759 | " \n", 760 | " \n", 761 | " \n", 762 | " \n", 763 | " \n", 764 | " \n", 765 | " \n", 766 | " \n", 767 | " \n", 768 | " \n", 769 | " \n", 770 | " \n", 771 | " \n", 772 | " \n", 773 | " \n", 774 | " \n", 775 | " \n", 776 | " \n", 777 | " \n", 778 | " \n", 779 | " \n", 780 | " \n", 781 | " \n", 782 | " \n", 783 | " \n", 784 | " \n", 785 | " \n", 786 | " \n", 787 | " \n", 788 | " \n", 789 | " \n", 790 | " \n", 791 | " \n", 792 | " \n", 793 | " \n", 794 | " \n", 795 | " \n", 796 | " \n", 797 | " \n", 798 | " \n", 799 | " \n", 800 | " \n", 801 | " \n", 802 | " \n", 803 | " \n", 804 | " \n", 805 | " \n", 806 | " \n", 807 | " \n", 808 | " \n", 809 | " \n", 810 | " \n", 811 | " \n", 812 | " \n", 813 | " \n", 814 | " \n", 815 | " \n", 816 | " \n", 817 | " \n", 818 | " \n", 819 | " \n", 820 | " \n", 821 | " \n", 822 | " \n", 823 | " \n", 824 | " \n", 825 | " \n", 826 | " \n", 827 | " \n", 828 | " \n", 829 | " \n", 830 | " \n", 831 | " \n", 832 | " \n", 833 | " \n", 834 | " \n", 835 | " \n", 836 | " \n", 837 | " \n", 838 | " \n", 839 | " \n", 840 | " \n", 841 | " \n", 842 | " \n", 843 | " \n", 844 | " \n", 845 | " \n", 846 | " \n", 847 | " \n", 848 | " \n", 849 | " \n", 850 | " \n", 851 | " \n", 852 | " \n", 853 | " \n", 854 | " \n", 855 | " \n", 856 | " \n", 857 | " \n", 858 | " \n", 859 | " \n", 860 | " \n", 861 | " \n", 862 | " \n", 863 | " \n", 864 | " \n", 865 | " \n", 866 | " \n", 867 | " \n", 868 | " \n", 869 | " \n", 870 | " \n", 871 | " \n", 872 | " \n", 873 | " \n", 874 | " \n", 875 | " \n", 876 | " \n", 877 | " \n", 878 | " \n", 879 | " \n", 880 | " \n", 881 | " \n", 882 | " \n", 883 | " \n", 884 | " \n", 885 | " \n", 886 | " \n", 887 | " \n", 888 | " \n", 889 | " \n", 890 | " \n", 891 | " \n", 892 | " \n", 893 | " \n", 894 | " \n", 895 | " \n", 896 | " \n", 897 | " \n", 898 | " \n", 899 | " \n", 900 | " \n", 901 | " \n", 902 | " \n", 903 | " \n", 904 | " \n", 905 | " \n", 906 | " \n", 907 | " \n", 908 | " \n", 909 | " \n", 910 | " \n", 911 | " \n", 912 | " \n", 913 | " \n", 914 | " \n", 915 | " \n", 916 | " \n", 917 | " \n", 918 | " \n", 919 | " \n", 920 | " \n", 921 | " \n", 922 | " \n", 923 | " \n", 924 | " \n", 925 | " \n", 926 | " \n", 927 | " \n", 928 | " \n", 929 | " \n", 930 | " \n", 931 | " \n", 932 | " \n", 933 | " \n", 934 | " \n", 935 | " \n", 936 | " \n", 937 | " \n", 938 | " \n", 939 | " \n", 940 | " \n", 941 | " \n", 942 | " \n", 943 | " \n", 944 | " \n", 945 | " \n", 946 | " \n", 947 | " \n", 948 | " \n", 949 | " \n", 950 | " \n", 951 | " \n", 952 | " \n", 953 | " \n", 954 | " \n", 955 | " \n", 956 | " \n", 957 | " \n", 958 | " \n", 959 | " \n", 960 | " \n", 961 | " \n", 962 | " \n", 963 | " \n", 964 | " \n", 965 | " \n", 966 | " \n", 967 | " \n", 968 | " \n", 969 | " \n", 970 | " \n", 971 | " \n", 972 | " \n", 973 | " \n", 974 | " \n", 975 | " \n", 976 | " \n", 977 | " \n", 978 | " \n", 979 | " \n", 980 | " \n", 981 | " \n", 982 | " \n", 983 | " \n", 984 | " \n", 985 | " \n", 986 | " \n", 987 | " \n", 988 | " \n", 989 | " \n", 990 | " \n", 991 | " \n", 992 | " \n", 993 | " \n", 994 | " \n", 995 | " \n", 996 | " \n", 997 | " \n", 998 | " \n", 999 | " \n", 1000 | " \n", 1001 | " \n", 1002 | " \n", 1003 | " \n", 1004 | " \n", 1005 | " \n", 1006 | "
factor
datesecID
2013-02-28801010.SI1.03
801020.SI6.22
801030.SI3.42
801040.SI1.64
801050.SI6.12
801080.SI0.82
801110.SI2.52
801120.SI5.35
801130.SI0.20
801150.SI4.69
801160.SI2.53
801170.SI2.58
801180.SI6.36
801200.SI1.64
801210.SI0.14
801230.SI0.25
2013-03-29801010.SI0.99
801020.SI6.08
801030.SI3.83
801040.SI1.67
801050.SI5.93
801080.SI1.02
801110.SI2.67
801120.SI5.58
801130.SI0.21
801150.SI5.26
801160.SI2.80
801170.SI2.66
801180.SI6.11
801200.SI1.67
.........
2014-11-28801790.SI16.28
801880.SI3.85
801890.SI2.16
2014-12-31801010.SI0.52
801020.SI2.79
801030.SI2.37
801040.SI1.42
801050.SI3.28
801080.SI1.56
801110.SI2.80
801120.SI4.23
801130.SI0.32
801150.SI4.71
801160.SI4.06
801170.SI2.89
801180.SI5.08
801200.SI1.98
801210.SI0.21
801230.SI0.45
801710.SI0.73
801720.SI4.66
801730.SI1.74
801740.SI2.19
801750.SI2.09
801760.SI2.98
801770.SI1.39
801780.SI20.12
801790.SI19.77
801880.SI3.35
801890.SI2.28
\n", 1007 | "

489 rows × 1 columns

\n", 1008 | "
" 1009 | ], 1010 | "text/plain": [ 1011 | "
\n", 1012 | "\n", 1013 | " \n", 1014 | " \n", 1015 | " \n", 1016 | " \n", 1017 | " \n", 1018 | " \n", 1019 | " \n", 1020 | " \n", 1021 | " \n", 1022 | " \n", 1023 | " \n", 1024 | " \n", 1025 | " \n", 1026 | " \n", 1027 | " \n", 1028 | " \n", 1029 | " \n", 1030 | " \n", 1031 | " \n", 1032 | " \n", 1033 | " \n", 1034 | " \n", 1035 | " \n", 1036 | " \n", 1037 | " \n", 1038 | " \n", 1039 | " \n", 1040 | " \n", 1041 | " \n", 1042 | " \n", 1043 | " \n", 1044 | " \n", 1045 | " \n", 1046 | " \n", 1047 | " \n", 1048 | " \n", 1049 | " \n", 1050 | " \n", 1051 | " \n", 1052 | " \n", 1053 | " \n", 1054 | " \n", 1055 | " \n", 1056 | " \n", 1057 | " \n", 1058 | " \n", 1059 | " \n", 1060 | " \n", 1061 | " \n", 1062 | " \n", 1063 | " \n", 1064 | " \n", 1065 | " \n", 1066 | " \n", 1067 | " \n", 1068 | " \n", 1069 | " \n", 1070 | " \n", 1071 | " \n", 1072 | " \n", 1073 | " \n", 1074 | " \n", 1075 | " \n", 1076 | " \n", 1077 | " \n", 1078 | " \n", 1079 | " \n", 1080 | " \n", 1081 | " \n", 1082 | " \n", 1083 | " \n", 1084 | " \n", 1085 | " \n", 1086 | " \n", 1087 | " \n", 1088 | " \n", 1089 | " \n", 1090 | " \n", 1091 | " \n", 1092 | " \n", 1093 | " \n", 1094 | " \n", 1095 | " \n", 1096 | " \n", 1097 | " \n", 1098 | " \n", 1099 | " \n", 1100 | " \n", 1101 | " \n", 1102 | " \n", 1103 | " \n", 1104 | " \n", 1105 | " \n", 1106 | " \n", 1107 | " \n", 1108 | " \n", 1109 | " \n", 1110 | " \n", 1111 | " \n", 1112 | " \n", 1113 | " \n", 1114 | " \n", 1115 | " \n", 1116 | " \n", 1117 | " \n", 1118 | " \n", 1119 | " \n", 1120 | " \n", 1121 | " \n", 1122 | " \n", 1123 | " \n", 1124 | " \n", 1125 | " \n", 1126 | " \n", 1127 | " \n", 1128 | " \n", 1129 | " \n", 1130 | " \n", 1131 | " \n", 1132 | " \n", 1133 | " \n", 1134 | " \n", 1135 | " \n", 1136 | " \n", 1137 | " \n", 1138 | " \n", 1139 | " \n", 1140 | " \n", 1141 | " \n", 1142 | " \n", 1143 | " \n", 1144 | " \n", 1145 | " \n", 1146 | " \n", 1147 | " \n", 1148 | " \n", 1149 | " \n", 1150 | " \n", 1151 | " \n", 1152 | " \n", 1153 | " \n", 1154 | " \n", 1155 | " \n", 1156 | " \n", 1157 | " \n", 1158 | " \n", 1159 | " \n", 1160 | " \n", 1161 | " \n", 1162 | " \n", 1163 | " \n", 1164 | " \n", 1165 | " \n", 1166 | " \n", 1167 | " \n", 1168 | " \n", 1169 | " \n", 1170 | " \n", 1171 | " \n", 1172 | " \n", 1173 | " \n", 1174 | " \n", 1175 | " \n", 1176 | " \n", 1177 | " \n", 1178 | " \n", 1179 | " \n", 1180 | " \n", 1181 | " \n", 1182 | " \n", 1183 | " \n", 1184 | " \n", 1185 | " \n", 1186 | " \n", 1187 | " \n", 1188 | " \n", 1189 | " \n", 1190 | " \n", 1191 | " \n", 1192 | " \n", 1193 | " \n", 1194 | " \n", 1195 | " \n", 1196 | " \n", 1197 | " \n", 1198 | " \n", 1199 | " \n", 1200 | " \n", 1201 | " \n", 1202 | " \n", 1203 | " \n", 1204 | " \n", 1205 | " \n", 1206 | " \n", 1207 | " \n", 1208 | " \n", 1209 | " \n", 1210 | " \n", 1211 | " \n", 1212 | " \n", 1213 | " \n", 1214 | " \n", 1215 | " \n", 1216 | " \n", 1217 | " \n", 1218 | " \n", 1219 | " \n", 1220 | " \n", 1221 | " \n", 1222 | " \n", 1223 | " \n", 1224 | " \n", 1225 | " \n", 1226 | " \n", 1227 | " \n", 1228 | " \n", 1229 | " \n", 1230 | " \n", 1231 | " \n", 1232 | " \n", 1233 | " \n", 1234 | " \n", 1235 | " \n", 1236 | " \n", 1237 | " \n", 1238 | " \n", 1239 | " \n", 1240 | " \n", 1241 | " \n", 1242 | " \n", 1243 | " \n", 1244 | " \n", 1245 | " \n", 1246 | " \n", 1247 | " \n", 1248 | " \n", 1249 | " \n", 1250 | " \n", 1251 | " \n", 1252 | " \n", 1253 | " \n", 1254 | " \n", 1255 | " \n", 1256 | " \n", 1257 | " \n", 1258 | " \n", 1259 | " \n", 1260 | " \n", 1261 | " \n", 1262 | " \n", 1263 | " \n", 1264 | " \n", 1265 | " \n", 1266 | " \n", 1267 | " \n", 1268 | " \n", 1269 | " \n", 1270 | " \n", 1271 | " \n", 1272 | " \n", 1273 | " \n", 1274 | " \n", 1275 | " \n", 1276 | "
factor
datesecID
2013-02-28801010.SI1.03
801020.SI6.22
801030.SI3.42
801040.SI1.64
801050.SI6.12
801080.SI0.82
801110.SI2.52
801120.SI5.35
801130.SI0.20
801150.SI4.69
801160.SI2.53
801170.SI2.58
801180.SI6.36
801200.SI1.64
801210.SI0.14
801230.SI0.25
2013-03-29801010.SI0.99
801020.SI6.08
801030.SI3.83
801040.SI1.67
801050.SI5.93
801080.SI1.02
801110.SI2.67
801120.SI5.58
801130.SI0.21
801150.SI5.26
801160.SI2.80
801170.SI2.66
801180.SI6.11
801200.SI1.67
.........
2014-11-28801790.SI16.28
801880.SI3.85
801890.SI2.16
2014-12-31801010.SI0.52
801020.SI2.79
801030.SI2.37
801040.SI1.42
801050.SI3.28
801080.SI1.56
801110.SI2.80
801120.SI4.23
801130.SI0.32
801150.SI4.71
801160.SI4.06
801170.SI2.89
801180.SI5.08
801200.SI1.98
801210.SI0.21
801230.SI0.45
801710.SI0.73
801720.SI4.66
801730.SI1.74
801740.SI2.19
801750.SI2.09
801760.SI2.98
801770.SI1.39
801780.SI20.12
801790.SI19.77
801880.SI3.35
801890.SI2.28
\n", 1277 | "

489 rows × 1 columns

\n", 1278 | "
" 1279 | ] 1280 | }, 1281 | "execution_count": 6, 1282 | "metadata": {}, 1283 | "output_type": "execute_result" 1284 | } 1285 | ], 1286 | "source": [ 1287 | "from WindAdapter import factor_load\n", 1288 | "from WindAdapter.enums import OutputFormat\n", 1289 | "\n", 1290 | "# 读取 2014年上半年 000001.SZ和000002.SZ的PB数据, 并保存成csv格式(默认数据频率为月频,数据格式为multi-index DataFrame)\n", 1291 | "#factor_load('2014-01-01', '2014-07-10', 'PB', sec_id=['000001.SZ', '000002.SZ'], is_index=False, save_file='PB.csv')\n", 1292 | "\n", 1293 | "# 读取全市场 2016年1月的每日收盘价,并保存成pickle格式\n", 1294 | "#factor_load('2014-01-01', '2014-07-10', 'close', sec_id='fullA', is_index=True, freq='D', save_file='close.pkl')\n", 1295 | "\n", 1296 | "# 读取沪深300成分股从2014年1月至3月,频率为每月(freq=M)的季度(tenor='3M')收益, 并保存成csv格式\n", 1297 | "factor_load('2014-01-01', '2014-03-31', 'return', sec_id='000300.SH', is_index=True, freq='M', tenor='3M', save_file='HS300_return_1Q.csv')\n", 1298 | "\n", 1299 | "\n", 1300 | "# 读取指数成分的行业权重分布\n", 1301 | "factor_load('2013-02-01', '2015-01-01', 'INDUSTRY_WEIGHT_C1', sec_id='000300.SH', save_file='300.csv')\n", 1302 | "\n", 1303 | "# 同时读取PB和MV数据\n", 1304 | "factor_load('2014-01-01', '2014-07-10', ['PB', 'MV'], sec_id=['000001.SZ', '000002.SZ'], is_index=False,\n", 1305 | " reset_col_names=True)" 1306 | ] 1307 | }, 1308 | { 1309 | "cell_type": "code", 1310 | "execution_count": 1, 1311 | "metadata": {}, 1312 | "outputs": [ 1313 | { 1314 | "name": "stderr", 1315 | "output_type": "stream", 1316 | "text": [ 1317 | "2017-04-28 13:58:40,135 - WindAdapter - CRITICAL - Reset path of data dict to C:\\data_dict_perso.csv\n" 1318 | ] 1319 | }, 1320 | { 1321 | "name": "stdout", 1322 | "output_type": "stream", 1323 | "text": [ 1324 | "Welcome to use Wind Quant API for Python (WindPy)!\nYou can use w.menu to help yourself to create commands(WSD,WSS,WST,WSI,WSQ,...)!\n\nCOPYRIGHT (C) 2016 WIND HONGHUI INFORMATION & TECHKNOLEWDGE CO., LTD. ALL RIGHTS RESERVED.\nIN NO CIRCUMSTANCE SHALL WIND BE RESPONSIBLE FOR ANY DAMAGES OR LOSSES CAUSED BY USING WIND QUANT API FOR Python.\n" 1325 | ] 1326 | } 1327 | ], 1328 | "source": [ 1329 | "from WindAdapter import reset_data_dict_path\n", 1330 | "\n", 1331 | "reset_data_dict_path(path='C:\\\\data_dict_perso.csv', path_type_abs=True)" 1332 | ] 1333 | }, 1334 | { 1335 | "cell_type": "code", 1336 | "execution_count": 5, 1337 | "metadata": {}, 1338 | "outputs": [], 1339 | "source": [ 1340 | "" 1341 | ] 1342 | }, 1343 | { 1344 | "cell_type": "code", 1345 | "execution_count": null, 1346 | "metadata": {}, 1347 | "outputs": [], 1348 | "source": [ 1349 | "" 1350 | ] 1351 | } 1352 | ], 1353 | "metadata": {}, 1354 | "nbformat": 4, 1355 | "nbformat_minor": 0 1356 | } 1357 | --------------------------------------------------------------------------------