├── 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 | | Latest Release |
4 |  |
5 |
6 |
7 |
8 |
9 | | Python version |
10 |  |
11 |
12 |
13 |
14 | | Build Status |
15 |  |
16 |
17 |
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 | " | Data_Dict | \n",
53 | " explanation | \n",
54 | "
\n",
55 | " \n",
56 | " | name | \n",
57 | " | \n",
58 | "
\n",
59 | " \n",
60 | " \n",
61 | " \n",
62 | " | MV | \n",
63 | " 总市值(不可回测) | \n",
64 | "
\n",
65 | " \n",
66 | " | PB | \n",
67 | " 市净率PB(LF) | \n",
68 | "
\n",
69 | " \n",
70 | " | STDQ | \n",
71 | " 区间换手率(基准 自由流通股本) | \n",
72 | "
\n",
73 | " \n",
74 | " | EquityGrowth_YoY | \n",
75 | " 净资产(同比增长率) | \n",
76 | "
\n",
77 | " \n",
78 | " | ROE | \n",
79 | " 净资产收益率(平均) | \n",
80 | "
\n",
81 | " \n",
82 | " | ProfitGrowth_Qr_YoY | \n",
83 | " 单季度 净利润同比增长率 | \n",
84 | "
\n",
85 | " \n",
86 | " | TO_adj | \n",
87 | " 区间日均换手率(基准 自由流通股本) | \n",
88 | "
\n",
89 | " \n",
90 | " | RETURN | \n",
91 | " 区间涨跌幅 | \n",
92 | "
\n",
93 | " \n",
94 | " | GrossProfit | \n",
95 | " 毛利 | \n",
96 | "
\n",
97 | " \n",
98 | " | EP | \n",
99 | " 扣除非经常性损益后的净利润(TTM) | \n",
100 | "
\n",
101 | " \n",
102 | " | SP | \n",
103 | " 营业总收入(TTM) | \n",
104 | "
\n",
105 | " \n",
106 | " | OHLCV | \n",
107 | " 开盘价、最高价、最低价、收盘价、成交量 | \n",
108 | "
\n",
109 | " \n",
110 | " | OPEN | \n",
111 | " 开盘价 | \n",
112 | "
\n",
113 | " \n",
114 | " | HIGH | \n",
115 | " 最高价 | \n",
116 | "
\n",
117 | " \n",
118 | " | LOW | \n",
119 | " 最低价 | \n",
120 | "
\n",
121 | " \n",
122 | " | CLOSE | \n",
123 | " 收盘价 | \n",
124 | "
\n",
125 | " \n",
126 | " | VOLUME | \n",
127 | " 成交量 | \n",
128 | "
\n",
129 | " \n",
130 | " | SW_C1 | \n",
131 | " 股票所属申万一级行业代码 | \n",
132 | "
\n",
133 | " \n",
134 | " | SW_C2 | \n",
135 | " 股票所属申万二级行业代码 | \n",
136 | "
\n",
137 | " \n",
138 | " | INDUSTRY_WEIGHT_C1 | \n",
139 | " 申万一级行业所占指数权重 | \n",
140 | "
\n",
141 | " \n",
142 | " | INDUSTRY_WEIGHT_C2 | \n",
143 | " 申万二级行业所占指数权重 | \n",
144 | "
\n",
145 | " \n",
146 | "
\n",
147 | "
"
148 | ],
149 | "text/plain": [
150 | "\n",
151 | "
\n",
152 | " \n",
153 | " \n",
154 | " | Data_Dict | \n",
155 | " explanation | \n",
156 | "
\n",
157 | " \n",
158 | " | name | \n",
159 | " | \n",
160 | "
\n",
161 | " \n",
162 | " \n",
163 | " \n",
164 | " | MV | \n",
165 | " 总市值(不可回测) | \n",
166 | "
\n",
167 | " \n",
168 | " | PB | \n",
169 | " 市净率PB(LF) | \n",
170 | "
\n",
171 | " \n",
172 | " | STDQ | \n",
173 | " 区间换手率(基准 自由流通股本) | \n",
174 | "
\n",
175 | " \n",
176 | " | EquityGrowth_YoY | \n",
177 | " 净资产(同比增长率) | \n",
178 | "
\n",
179 | " \n",
180 | " | ROE | \n",
181 | " 净资产收益率(平均) | \n",
182 | "
\n",
183 | " \n",
184 | " | ProfitGrowth_Qr_YoY | \n",
185 | " 单季度 净利润同比增长率 | \n",
186 | "
\n",
187 | " \n",
188 | " | TO_adj | \n",
189 | " 区间日均换手率(基准 自由流通股本) | \n",
190 | "
\n",
191 | " \n",
192 | " | RETURN | \n",
193 | " 区间涨跌幅 | \n",
194 | "
\n",
195 | " \n",
196 | " | GrossProfit | \n",
197 | " 毛利 | \n",
198 | "
\n",
199 | " \n",
200 | " | EP | \n",
201 | " 扣除非经常性损益后的净利润(TTM) | \n",
202 | "
\n",
203 | " \n",
204 | " | SP | \n",
205 | " 营业总收入(TTM) | \n",
206 | "
\n",
207 | " \n",
208 | " | OHLCV | \n",
209 | " 开盘价、最高价、最低价、收盘价、成交量 | \n",
210 | "
\n",
211 | " \n",
212 | " | OPEN | \n",
213 | " 开盘价 | \n",
214 | "
\n",
215 | " \n",
216 | " | HIGH | \n",
217 | " 最高价 | \n",
218 | "
\n",
219 | " \n",
220 | " | LOW | \n",
221 | " 最低价 | \n",
222 | "
\n",
223 | " \n",
224 | " | CLOSE | \n",
225 | " 收盘价 | \n",
226 | "
\n",
227 | " \n",
228 | " | VOLUME | \n",
229 | " 成交量 | \n",
230 | "
\n",
231 | " \n",
232 | " | SW_C1 | \n",
233 | " 股票所属申万一级行业代码 | \n",
234 | "
\n",
235 | " \n",
236 | " | SW_C2 | \n",
237 | " 股票所属申万二级行业代码 | \n",
238 | "
\n",
239 | " \n",
240 | " | INDUSTRY_WEIGHT_C1 | \n",
241 | " 申万一级行业所占指数权重 | \n",
242 | "
\n",
243 | " \n",
244 | " | INDUSTRY_WEIGHT_C2 | \n",
245 | " 申万二级行业所占指数权重 | \n",
246 | "
\n",
247 | " \n",
248 | "
\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 | " | Data_Dict | \n",
271 | " api | \n",
272 | " indicator | \n",
273 | " priceadj | \n",
274 | " unit | \n",
275 | " explanation | \n",
276 | " type | \n",
277 | "
\n",
278 | " \n",
279 | " | name | \n",
280 | " | \n",
281 | " | \n",
282 | " | \n",
283 | " | \n",
284 | " | \n",
285 | " | \n",
286 | "
\n",
287 | " \n",
288 | " \n",
289 | " \n",
290 | " | MV | \n",
291 | " wsd | \n",
292 | " mkt_cap | \n",
293 | " F | \n",
294 | " 1.0 | \n",
295 | " 总市值(不可回测) | \n",
296 | " 规模 | \n",
297 | "
\n",
298 | " \n",
299 | " | PB | \n",
300 | " wsd | \n",
301 | " pb_lf | \n",
302 | " F | \n",
303 | " NaN | \n",
304 | " 市净率PB(LF) | \n",
305 | " 价值 | \n",
306 | "
\n",
307 | " \n",
308 | " | STDQ | \n",
309 | " wss | \n",
310 | " turn_free_per | \n",
311 | " NaN | \n",
312 | " NaN | \n",
313 | " 区间换手率(基准 自由流通股本) | \n",
314 | " 流动性 | \n",
315 | "
\n",
316 | " \n",
317 | " | EquityGrowth_YoY | \n",
318 | " wsd | \n",
319 | " yoy_equity | \n",
320 | " NaN | \n",
321 | " NaN | \n",
322 | " 净资产(同比增长率) | \n",
323 | " 成长 | \n",
324 | "
\n",
325 | " \n",
326 | " | ROE | \n",
327 | " wsd | \n",
328 | " roe_avg | \n",
329 | " NaN | \n",
330 | " NaN | \n",
331 | " 净资产收益率(平均) | \n",
332 | " 盈利 | \n",
333 | "
\n",
334 | " \n",
335 | " | ProfitGrowth_Qr_YoY | \n",
336 | " wsd | \n",
337 | " qfa_yoyprofit | \n",
338 | " NaN | \n",
339 | " NaN | \n",
340 | " 单季度 净利润同比增长率 | \n",
341 | " 盈利 | \n",
342 | "
\n",
343 | " \n",
344 | " | TO_adj | \n",
345 | " wss | \n",
346 | " avg_turn_free_per | \n",
347 | " NaN | \n",
348 | " NaN | \n",
349 | " 区间日均换手率(基准 自由流通股本) | \n",
350 | " 流动性 | \n",
351 | "
\n",
352 | " \n",
353 | " | RETURN | \n",
354 | " wss | \n",
355 | " pct_chg_per | \n",
356 | " NaN | \n",
357 | " NaN | \n",
358 | " 区间涨跌幅 | \n",
359 | " 估值 | \n",
360 | "
\n",
361 | " \n",
362 | " | GrossProfit | \n",
363 | " wsd | \n",
364 | " grossmargin | \n",
365 | " NaN | \n",
366 | " 100000000.0 | \n",
367 | " 毛利 | \n",
368 | " 盈利 | \n",
369 | "
\n",
370 | " \n",
371 | " | EP | \n",
372 | " wsd | \n",
373 | " deductedprofit_ttm | \n",
374 | " NaN | \n",
375 | " 100000000.0 | \n",
376 | " 扣除非经常性损益后的净利润(TTM) | \n",
377 | " 盈利 | \n",
378 | "
\n",
379 | " \n",
380 | " | SP | \n",
381 | " wsd | \n",
382 | " gr_ttm | \n",
383 | " NaN | \n",
384 | " 100000000.0 | \n",
385 | " 营业总收入(TTM) | \n",
386 | " 盈利 | \n",
387 | "
\n",
388 | " \n",
389 | " | OHLCV | \n",
390 | " wsd | \n",
391 | " open,high,low,close,volume | \n",
392 | " NaN | \n",
393 | " NaN | \n",
394 | " 开盘价、最高价、最低价、收盘价、成交量 | \n",
395 | " 技术 | \n",
396 | "
\n",
397 | " \n",
398 | " | OPEN | \n",
399 | " wsd | \n",
400 | " open | \n",
401 | " F | \n",
402 | " NaN | \n",
403 | " 开盘价 | \n",
404 | " 技术 | \n",
405 | "
\n",
406 | " \n",
407 | " | HIGH | \n",
408 | " wsd | \n",
409 | " high | \n",
410 | " F | \n",
411 | " NaN | \n",
412 | " 最高价 | \n",
413 | " 技术 | \n",
414 | "
\n",
415 | " \n",
416 | " | LOW | \n",
417 | " wsd | \n",
418 | " low | \n",
419 | " F | \n",
420 | " NaN | \n",
421 | " 最低价 | \n",
422 | " 技术 | \n",
423 | "
\n",
424 | " \n",
425 | " | CLOSE | \n",
426 | " wsd | \n",
427 | " close | \n",
428 | " F | \n",
429 | " NaN | \n",
430 | " 收盘价 | \n",
431 | " 技术 | \n",
432 | "
\n",
433 | " \n",
434 | " | VOLUME | \n",
435 | " wsd | \n",
436 | " volume | \n",
437 | " F | \n",
438 | " NaN | \n",
439 | " 成交量 | \n",
440 | " 技术 | \n",
441 | "
\n",
442 | " \n",
443 | " | SW_C1 | \n",
444 | " wsd | \n",
445 | " indexcode_sw | \n",
446 | " NaN | \n",
447 | " NaN | \n",
448 | " 股票所属申万一级行业代码 | \n",
449 | " 基本信息 | \n",
450 | "
\n",
451 | " \n",
452 | " | SW_C2 | \n",
453 | " wsd | \n",
454 | " indexcode_sw | \n",
455 | " NaN | \n",
456 | " NaN | \n",
457 | " 股票所属申万二级行业代码 | \n",
458 | " 基本信息 | \n",
459 | "
\n",
460 | " \n",
461 | " | INDUSTRY_WEIGHT_C1 | \n",
462 | " NaN | \n",
463 | " NaN | \n",
464 | " NaN | \n",
465 | " NaN | \n",
466 | " 申万一级行业所占指数权重 | \n",
467 | " 基本信息 | \n",
468 | "
\n",
469 | " \n",
470 | " | INDUSTRY_WEIGHT_C2 | \n",
471 | " NaN | \n",
472 | " NaN | \n",
473 | " NaN | \n",
474 | " NaN | \n",
475 | " 申万二级行业所占指数权重 | \n",
476 | " 基本信息 | \n",
477 | "
\n",
478 | " \n",
479 | "
\n",
480 | "
"
481 | ],
482 | "text/plain": [
483 | "\n",
484 | "
\n",
485 | " \n",
486 | " \n",
487 | " | Data_Dict | \n",
488 | " api | \n",
489 | " indicator | \n",
490 | " priceadj | \n",
491 | " unit | \n",
492 | " explanation | \n",
493 | " type | \n",
494 | "
\n",
495 | " \n",
496 | " | name | \n",
497 | " | \n",
498 | " | \n",
499 | " | \n",
500 | " | \n",
501 | " | \n",
502 | " | \n",
503 | "
\n",
504 | " \n",
505 | " \n",
506 | " \n",
507 | " | MV | \n",
508 | " wsd | \n",
509 | " mkt_cap | \n",
510 | " F | \n",
511 | " 1.0 | \n",
512 | " 总市值(不可回测) | \n",
513 | " 规模 | \n",
514 | "
\n",
515 | " \n",
516 | " | PB | \n",
517 | " wsd | \n",
518 | " pb_lf | \n",
519 | " F | \n",
520 | " NaN | \n",
521 | " 市净率PB(LF) | \n",
522 | " 价值 | \n",
523 | "
\n",
524 | " \n",
525 | " | STDQ | \n",
526 | " wss | \n",
527 | " turn_free_per | \n",
528 | " NaN | \n",
529 | " NaN | \n",
530 | " 区间换手率(基准 自由流通股本) | \n",
531 | " 流动性 | \n",
532 | "
\n",
533 | " \n",
534 | " | EquityGrowth_YoY | \n",
535 | " wsd | \n",
536 | " yoy_equity | \n",
537 | " NaN | \n",
538 | " NaN | \n",
539 | " 净资产(同比增长率) | \n",
540 | " 成长 | \n",
541 | "
\n",
542 | " \n",
543 | " | ROE | \n",
544 | " wsd | \n",
545 | " roe_avg | \n",
546 | " NaN | \n",
547 | " NaN | \n",
548 | " 净资产收益率(平均) | \n",
549 | " 盈利 | \n",
550 | "
\n",
551 | " \n",
552 | " | ProfitGrowth_Qr_YoY | \n",
553 | " wsd | \n",
554 | " qfa_yoyprofit | \n",
555 | " NaN | \n",
556 | " NaN | \n",
557 | " 单季度 净利润同比增长率 | \n",
558 | " 盈利 | \n",
559 | "
\n",
560 | " \n",
561 | " | TO_adj | \n",
562 | " wss | \n",
563 | " avg_turn_free_per | \n",
564 | " NaN | \n",
565 | " NaN | \n",
566 | " 区间日均换手率(基准 自由流通股本) | \n",
567 | " 流动性 | \n",
568 | "
\n",
569 | " \n",
570 | " | RETURN | \n",
571 | " wss | \n",
572 | " pct_chg_per | \n",
573 | " NaN | \n",
574 | " NaN | \n",
575 | " 区间涨跌幅 | \n",
576 | " 估值 | \n",
577 | "
\n",
578 | " \n",
579 | " | GrossProfit | \n",
580 | " wsd | \n",
581 | " grossmargin | \n",
582 | " NaN | \n",
583 | " 100000000.0 | \n",
584 | " 毛利 | \n",
585 | " 盈利 | \n",
586 | "
\n",
587 | " \n",
588 | " | EP | \n",
589 | " wsd | \n",
590 | " deductedprofit_ttm | \n",
591 | " NaN | \n",
592 | " 100000000.0 | \n",
593 | " 扣除非经常性损益后的净利润(TTM) | \n",
594 | " 盈利 | \n",
595 | "
\n",
596 | " \n",
597 | " | SP | \n",
598 | " wsd | \n",
599 | " gr_ttm | \n",
600 | " NaN | \n",
601 | " 100000000.0 | \n",
602 | " 营业总收入(TTM) | \n",
603 | " 盈利 | \n",
604 | "
\n",
605 | " \n",
606 | " | OHLCV | \n",
607 | " wsd | \n",
608 | " open,high,low,close,volume | \n",
609 | " NaN | \n",
610 | " NaN | \n",
611 | " 开盘价、最高价、最低价、收盘价、成交量 | \n",
612 | " 技术 | \n",
613 | "
\n",
614 | " \n",
615 | " | OPEN | \n",
616 | " wsd | \n",
617 | " open | \n",
618 | " F | \n",
619 | " NaN | \n",
620 | " 开盘价 | \n",
621 | " 技术 | \n",
622 | "
\n",
623 | " \n",
624 | " | HIGH | \n",
625 | " wsd | \n",
626 | " high | \n",
627 | " F | \n",
628 | " NaN | \n",
629 | " 最高价 | \n",
630 | " 技术 | \n",
631 | "
\n",
632 | " \n",
633 | " | LOW | \n",
634 | " wsd | \n",
635 | " low | \n",
636 | " F | \n",
637 | " NaN | \n",
638 | " 最低价 | \n",
639 | " 技术 | \n",
640 | "
\n",
641 | " \n",
642 | " | CLOSE | \n",
643 | " wsd | \n",
644 | " close | \n",
645 | " F | \n",
646 | " NaN | \n",
647 | " 收盘价 | \n",
648 | " 技术 | \n",
649 | "
\n",
650 | " \n",
651 | " | VOLUME | \n",
652 | " wsd | \n",
653 | " volume | \n",
654 | " F | \n",
655 | " NaN | \n",
656 | " 成交量 | \n",
657 | " 技术 | \n",
658 | "
\n",
659 | " \n",
660 | " | SW_C1 | \n",
661 | " wsd | \n",
662 | " indexcode_sw | \n",
663 | " NaN | \n",
664 | " NaN | \n",
665 | " 股票所属申万一级行业代码 | \n",
666 | " 基本信息 | \n",
667 | "
\n",
668 | " \n",
669 | " | SW_C2 | \n",
670 | " wsd | \n",
671 | " indexcode_sw | \n",
672 | " NaN | \n",
673 | " NaN | \n",
674 | " 股票所属申万二级行业代码 | \n",
675 | " 基本信息 | \n",
676 | "
\n",
677 | " \n",
678 | " | INDUSTRY_WEIGHT_C1 | \n",
679 | " NaN | \n",
680 | " NaN | \n",
681 | " NaN | \n",
682 | " NaN | \n",
683 | " 申万一级行业所占指数权重 | \n",
684 | " 基本信息 | \n",
685 | "
\n",
686 | " \n",
687 | " | INDUSTRY_WEIGHT_C2 | \n",
688 | " NaN | \n",
689 | " NaN | \n",
690 | " NaN | \n",
691 | " NaN | \n",
692 | " 申万二级行业所占指数权重 | \n",
693 | " 基本信息 | \n",
694 | "
\n",
695 | " \n",
696 | "
\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 | " factor | \n",
748 | "
\n",
749 | " \n",
750 | " | date | \n",
751 | " secID | \n",
752 | " | \n",
753 | "
\n",
754 | " \n",
755 | " \n",
756 | " \n",
757 | " | 2013-02-28 | \n",
758 | " 801010.SI | \n",
759 | " 1.03 | \n",
760 | "
\n",
761 | " \n",
762 | " | 801020.SI | \n",
763 | " 6.22 | \n",
764 | "
\n",
765 | " \n",
766 | " | 801030.SI | \n",
767 | " 3.42 | \n",
768 | "
\n",
769 | " \n",
770 | " | 801040.SI | \n",
771 | " 1.64 | \n",
772 | "
\n",
773 | " \n",
774 | " | 801050.SI | \n",
775 | " 6.12 | \n",
776 | "
\n",
777 | " \n",
778 | " | 801080.SI | \n",
779 | " 0.82 | \n",
780 | "
\n",
781 | " \n",
782 | " | 801110.SI | \n",
783 | " 2.52 | \n",
784 | "
\n",
785 | " \n",
786 | " | 801120.SI | \n",
787 | " 5.35 | \n",
788 | "
\n",
789 | " \n",
790 | " | 801130.SI | \n",
791 | " 0.20 | \n",
792 | "
\n",
793 | " \n",
794 | " | 801150.SI | \n",
795 | " 4.69 | \n",
796 | "
\n",
797 | " \n",
798 | " | 801160.SI | \n",
799 | " 2.53 | \n",
800 | "
\n",
801 | " \n",
802 | " | 801170.SI | \n",
803 | " 2.58 | \n",
804 | "
\n",
805 | " \n",
806 | " | 801180.SI | \n",
807 | " 6.36 | \n",
808 | "
\n",
809 | " \n",
810 | " | 801200.SI | \n",
811 | " 1.64 | \n",
812 | "
\n",
813 | " \n",
814 | " | 801210.SI | \n",
815 | " 0.14 | \n",
816 | "
\n",
817 | " \n",
818 | " | 801230.SI | \n",
819 | " 0.25 | \n",
820 | "
\n",
821 | " \n",
822 | " | 2013-03-29 | \n",
823 | " 801010.SI | \n",
824 | " 0.99 | \n",
825 | "
\n",
826 | " \n",
827 | " | 801020.SI | \n",
828 | " 6.08 | \n",
829 | "
\n",
830 | " \n",
831 | " | 801030.SI | \n",
832 | " 3.83 | \n",
833 | "
\n",
834 | " \n",
835 | " | 801040.SI | \n",
836 | " 1.67 | \n",
837 | "
\n",
838 | " \n",
839 | " | 801050.SI | \n",
840 | " 5.93 | \n",
841 | "
\n",
842 | " \n",
843 | " | 801080.SI | \n",
844 | " 1.02 | \n",
845 | "
\n",
846 | " \n",
847 | " | 801110.SI | \n",
848 | " 2.67 | \n",
849 | "
\n",
850 | " \n",
851 | " | 801120.SI | \n",
852 | " 5.58 | \n",
853 | "
\n",
854 | " \n",
855 | " | 801130.SI | \n",
856 | " 0.21 | \n",
857 | "
\n",
858 | " \n",
859 | " | 801150.SI | \n",
860 | " 5.26 | \n",
861 | "
\n",
862 | " \n",
863 | " | 801160.SI | \n",
864 | " 2.80 | \n",
865 | "
\n",
866 | " \n",
867 | " | 801170.SI | \n",
868 | " 2.66 | \n",
869 | "
\n",
870 | " \n",
871 | " | 801180.SI | \n",
872 | " 6.11 | \n",
873 | "
\n",
874 | " \n",
875 | " | 801200.SI | \n",
876 | " 1.67 | \n",
877 | "
\n",
878 | " \n",
879 | " | ... | \n",
880 | " ... | \n",
881 | " ... | \n",
882 | "
\n",
883 | " \n",
884 | " | 2014-11-28 | \n",
885 | " 801790.SI | \n",
886 | " 16.28 | \n",
887 | "
\n",
888 | " \n",
889 | " | 801880.SI | \n",
890 | " 3.85 | \n",
891 | "
\n",
892 | " \n",
893 | " | 801890.SI | \n",
894 | " 2.16 | \n",
895 | "
\n",
896 | " \n",
897 | " | 2014-12-31 | \n",
898 | " 801010.SI | \n",
899 | " 0.52 | \n",
900 | "
\n",
901 | " \n",
902 | " | 801020.SI | \n",
903 | " 2.79 | \n",
904 | "
\n",
905 | " \n",
906 | " | 801030.SI | \n",
907 | " 2.37 | \n",
908 | "
\n",
909 | " \n",
910 | " | 801040.SI | \n",
911 | " 1.42 | \n",
912 | "
\n",
913 | " \n",
914 | " | 801050.SI | \n",
915 | " 3.28 | \n",
916 | "
\n",
917 | " \n",
918 | " | 801080.SI | \n",
919 | " 1.56 | \n",
920 | "
\n",
921 | " \n",
922 | " | 801110.SI | \n",
923 | " 2.80 | \n",
924 | "
\n",
925 | " \n",
926 | " | 801120.SI | \n",
927 | " 4.23 | \n",
928 | "
\n",
929 | " \n",
930 | " | 801130.SI | \n",
931 | " 0.32 | \n",
932 | "
\n",
933 | " \n",
934 | " | 801150.SI | \n",
935 | " 4.71 | \n",
936 | "
\n",
937 | " \n",
938 | " | 801160.SI | \n",
939 | " 4.06 | \n",
940 | "
\n",
941 | " \n",
942 | " | 801170.SI | \n",
943 | " 2.89 | \n",
944 | "
\n",
945 | " \n",
946 | " | 801180.SI | \n",
947 | " 5.08 | \n",
948 | "
\n",
949 | " \n",
950 | " | 801200.SI | \n",
951 | " 1.98 | \n",
952 | "
\n",
953 | " \n",
954 | " | 801210.SI | \n",
955 | " 0.21 | \n",
956 | "
\n",
957 | " \n",
958 | " | 801230.SI | \n",
959 | " 0.45 | \n",
960 | "
\n",
961 | " \n",
962 | " | 801710.SI | \n",
963 | " 0.73 | \n",
964 | "
\n",
965 | " \n",
966 | " | 801720.SI | \n",
967 | " 4.66 | \n",
968 | "
\n",
969 | " \n",
970 | " | 801730.SI | \n",
971 | " 1.74 | \n",
972 | "
\n",
973 | " \n",
974 | " | 801740.SI | \n",
975 | " 2.19 | \n",
976 | "
\n",
977 | " \n",
978 | " | 801750.SI | \n",
979 | " 2.09 | \n",
980 | "
\n",
981 | " \n",
982 | " | 801760.SI | \n",
983 | " 2.98 | \n",
984 | "
\n",
985 | " \n",
986 | " | 801770.SI | \n",
987 | " 1.39 | \n",
988 | "
\n",
989 | " \n",
990 | " | 801780.SI | \n",
991 | " 20.12 | \n",
992 | "
\n",
993 | " \n",
994 | " | 801790.SI | \n",
995 | " 19.77 | \n",
996 | "
\n",
997 | " \n",
998 | " | 801880.SI | \n",
999 | " 3.35 | \n",
1000 | "
\n",
1001 | " \n",
1002 | " | 801890.SI | \n",
1003 | " 2.28 | \n",
1004 | "
\n",
1005 | " \n",
1006 | "
\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 | " factor | \n",
1018 | "
\n",
1019 | " \n",
1020 | " | date | \n",
1021 | " secID | \n",
1022 | " | \n",
1023 | "
\n",
1024 | " \n",
1025 | " \n",
1026 | " \n",
1027 | " | 2013-02-28 | \n",
1028 | " 801010.SI | \n",
1029 | " 1.03 | \n",
1030 | "
\n",
1031 | " \n",
1032 | " | 801020.SI | \n",
1033 | " 6.22 | \n",
1034 | "
\n",
1035 | " \n",
1036 | " | 801030.SI | \n",
1037 | " 3.42 | \n",
1038 | "
\n",
1039 | " \n",
1040 | " | 801040.SI | \n",
1041 | " 1.64 | \n",
1042 | "
\n",
1043 | " \n",
1044 | " | 801050.SI | \n",
1045 | " 6.12 | \n",
1046 | "
\n",
1047 | " \n",
1048 | " | 801080.SI | \n",
1049 | " 0.82 | \n",
1050 | "
\n",
1051 | " \n",
1052 | " | 801110.SI | \n",
1053 | " 2.52 | \n",
1054 | "
\n",
1055 | " \n",
1056 | " | 801120.SI | \n",
1057 | " 5.35 | \n",
1058 | "
\n",
1059 | " \n",
1060 | " | 801130.SI | \n",
1061 | " 0.20 | \n",
1062 | "
\n",
1063 | " \n",
1064 | " | 801150.SI | \n",
1065 | " 4.69 | \n",
1066 | "
\n",
1067 | " \n",
1068 | " | 801160.SI | \n",
1069 | " 2.53 | \n",
1070 | "
\n",
1071 | " \n",
1072 | " | 801170.SI | \n",
1073 | " 2.58 | \n",
1074 | "
\n",
1075 | " \n",
1076 | " | 801180.SI | \n",
1077 | " 6.36 | \n",
1078 | "
\n",
1079 | " \n",
1080 | " | 801200.SI | \n",
1081 | " 1.64 | \n",
1082 | "
\n",
1083 | " \n",
1084 | " | 801210.SI | \n",
1085 | " 0.14 | \n",
1086 | "
\n",
1087 | " \n",
1088 | " | 801230.SI | \n",
1089 | " 0.25 | \n",
1090 | "
\n",
1091 | " \n",
1092 | " | 2013-03-29 | \n",
1093 | " 801010.SI | \n",
1094 | " 0.99 | \n",
1095 | "
\n",
1096 | " \n",
1097 | " | 801020.SI | \n",
1098 | " 6.08 | \n",
1099 | "
\n",
1100 | " \n",
1101 | " | 801030.SI | \n",
1102 | " 3.83 | \n",
1103 | "
\n",
1104 | " \n",
1105 | " | 801040.SI | \n",
1106 | " 1.67 | \n",
1107 | "
\n",
1108 | " \n",
1109 | " | 801050.SI | \n",
1110 | " 5.93 | \n",
1111 | "
\n",
1112 | " \n",
1113 | " | 801080.SI | \n",
1114 | " 1.02 | \n",
1115 | "
\n",
1116 | " \n",
1117 | " | 801110.SI | \n",
1118 | " 2.67 | \n",
1119 | "
\n",
1120 | " \n",
1121 | " | 801120.SI | \n",
1122 | " 5.58 | \n",
1123 | "
\n",
1124 | " \n",
1125 | " | 801130.SI | \n",
1126 | " 0.21 | \n",
1127 | "
\n",
1128 | " \n",
1129 | " | 801150.SI | \n",
1130 | " 5.26 | \n",
1131 | "
\n",
1132 | " \n",
1133 | " | 801160.SI | \n",
1134 | " 2.80 | \n",
1135 | "
\n",
1136 | " \n",
1137 | " | 801170.SI | \n",
1138 | " 2.66 | \n",
1139 | "
\n",
1140 | " \n",
1141 | " | 801180.SI | \n",
1142 | " 6.11 | \n",
1143 | "
\n",
1144 | " \n",
1145 | " | 801200.SI | \n",
1146 | " 1.67 | \n",
1147 | "
\n",
1148 | " \n",
1149 | " | ... | \n",
1150 | " ... | \n",
1151 | " ... | \n",
1152 | "
\n",
1153 | " \n",
1154 | " | 2014-11-28 | \n",
1155 | " 801790.SI | \n",
1156 | " 16.28 | \n",
1157 | "
\n",
1158 | " \n",
1159 | " | 801880.SI | \n",
1160 | " 3.85 | \n",
1161 | "
\n",
1162 | " \n",
1163 | " | 801890.SI | \n",
1164 | " 2.16 | \n",
1165 | "
\n",
1166 | " \n",
1167 | " | 2014-12-31 | \n",
1168 | " 801010.SI | \n",
1169 | " 0.52 | \n",
1170 | "
\n",
1171 | " \n",
1172 | " | 801020.SI | \n",
1173 | " 2.79 | \n",
1174 | "
\n",
1175 | " \n",
1176 | " | 801030.SI | \n",
1177 | " 2.37 | \n",
1178 | "
\n",
1179 | " \n",
1180 | " | 801040.SI | \n",
1181 | " 1.42 | \n",
1182 | "
\n",
1183 | " \n",
1184 | " | 801050.SI | \n",
1185 | " 3.28 | \n",
1186 | "
\n",
1187 | " \n",
1188 | " | 801080.SI | \n",
1189 | " 1.56 | \n",
1190 | "
\n",
1191 | " \n",
1192 | " | 801110.SI | \n",
1193 | " 2.80 | \n",
1194 | "
\n",
1195 | " \n",
1196 | " | 801120.SI | \n",
1197 | " 4.23 | \n",
1198 | "
\n",
1199 | " \n",
1200 | " | 801130.SI | \n",
1201 | " 0.32 | \n",
1202 | "
\n",
1203 | " \n",
1204 | " | 801150.SI | \n",
1205 | " 4.71 | \n",
1206 | "
\n",
1207 | " \n",
1208 | " | 801160.SI | \n",
1209 | " 4.06 | \n",
1210 | "
\n",
1211 | " \n",
1212 | " | 801170.SI | \n",
1213 | " 2.89 | \n",
1214 | "
\n",
1215 | " \n",
1216 | " | 801180.SI | \n",
1217 | " 5.08 | \n",
1218 | "
\n",
1219 | " \n",
1220 | " | 801200.SI | \n",
1221 | " 1.98 | \n",
1222 | "
\n",
1223 | " \n",
1224 | " | 801210.SI | \n",
1225 | " 0.21 | \n",
1226 | "
\n",
1227 | " \n",
1228 | " | 801230.SI | \n",
1229 | " 0.45 | \n",
1230 | "
\n",
1231 | " \n",
1232 | " | 801710.SI | \n",
1233 | " 0.73 | \n",
1234 | "
\n",
1235 | " \n",
1236 | " | 801720.SI | \n",
1237 | " 4.66 | \n",
1238 | "
\n",
1239 | " \n",
1240 | " | 801730.SI | \n",
1241 | " 1.74 | \n",
1242 | "
\n",
1243 | " \n",
1244 | " | 801740.SI | \n",
1245 | " 2.19 | \n",
1246 | "
\n",
1247 | " \n",
1248 | " | 801750.SI | \n",
1249 | " 2.09 | \n",
1250 | "
\n",
1251 | " \n",
1252 | " | 801760.SI | \n",
1253 | " 2.98 | \n",
1254 | "
\n",
1255 | " \n",
1256 | " | 801770.SI | \n",
1257 | " 1.39 | \n",
1258 | "
\n",
1259 | " \n",
1260 | " | 801780.SI | \n",
1261 | " 20.12 | \n",
1262 | "
\n",
1263 | " \n",
1264 | " | 801790.SI | \n",
1265 | " 19.77 | \n",
1266 | "
\n",
1267 | " \n",
1268 | " | 801880.SI | \n",
1269 | " 3.35 | \n",
1270 | "
\n",
1271 | " \n",
1272 | " | 801890.SI | \n",
1273 | " 2.28 | \n",
1274 | "
\n",
1275 | " \n",
1276 | "
\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 |
--------------------------------------------------------------------------------