├── .gitignore
├── GuGu
├── __init__.py
├── base.py
├── billboard.py
├── classify.py
├── config.py
├── lowriskintarb.py
├── macro.py
├── marketdata.py
├── reference.py
├── stockdata.py
├── stockinfo.py
└── utility.py
├── LICENSE
├── README.md
├── setup.cfg
└── setup.py
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | __pycache__
3 | build
4 | dist
5 | GuGu.egg-info
6 |
--------------------------------------------------------------------------------
/GuGu/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 |
3 | __version__ = '0.1.0'
4 | __author__ = 'TabQ'
5 |
6 | from GuGu.billboard import (BillBoard)
7 |
8 | from GuGu.classify import (Classify)
9 |
10 | from GuGu.lowriskintarb import (LowRiskIntArb)
11 |
12 | from GuGu.macro import (Macro)
13 |
14 | from GuGu.marketdata import (MarketData)
15 |
16 | from GuGu.reference import (Reference)
17 |
18 | from GuGu.stockdata import (StockData)
19 |
20 | from GuGu.stockinfo import (StockInfo)
21 |
22 | from GuGu.utility import (Utility)
23 |
--------------------------------------------------------------------------------
/GuGu/base.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | """
3 | 基础类
4 | Created on 2018/12/27
5 | @author: TabQ
6 | @group : GuGu
7 | @contact: 16621596@qq.com
8 | """
9 |
10 | import pandas as pd
11 | import sys
12 | import requests
13 | from requests.adapters import HTTPAdapter
14 | from urllib3.util import Retry
15 | import config as cf
16 |
17 |
18 | class Base():
19 | def __init__(self, pandas=True, inter=True):
20 | self.__pandas = False if not pandas else True
21 | self._PY3 = (sys.version_info[0] >= 3)
22 | self._inter = False if not inter else True # 交互模式
23 |
24 | self._session = requests.Session()
25 | retry = Retry(connect=5, backoff_factor=1)
26 | adapter = HTTPAdapter(max_retries=retry)
27 | self._session.mount('http://', adapter)
28 | self._session.mount('https://', adapter)
29 | self._session.keep_alive = False
30 |
31 | self._data = pd.DataFrame()
32 |
33 |
34 | def _result(self):
35 | """
36 | 返回结果:使用pandas时返回DataFrame否则返回list
37 | Parameters
38 | -----
39 | dataframe:pandas.DataFrame
40 | index:string
41 | 返回dict时选用的键 e.g. code
42 | return
43 | -----
44 | pandas.DataFrame or dict
45 | """
46 | if self._data.empty:
47 | return None
48 | elif self.__pandas:
49 | return self._data
50 | else:
51 | return self._data.to_dict('records')
52 |
53 |
54 | def output(self, full=False):
55 | print('')
56 |
57 | if not full:
58 | print(self._data)
59 | else:
60 | pd.set_option('display.max_columns', None)
61 | pd.set_option('display.max_rows', None)
62 | pd.set_option('max_colwidth',100)
63 |
64 | print(self._data)
65 |
66 |
67 | def getPandas(self):
68 | return self.__pandas
69 |
70 |
71 | def setPandas(self, pandas=True):
72 | self.__pandas = pandas
73 |
74 |
75 | def getInter(self):
76 | """
77 | 获取交互模式状态
78 | return
79 | ------
80 | True or False
81 | """
82 | return self._inter
83 |
84 |
85 | def setInter(self, inter=False):
86 | """
87 | 设置交互模式
88 | Parameters
89 | ------
90 | inter: bool
91 | """
92 | self._inter = inter
93 |
94 |
95 | def _writeHead(self):
96 | if self._inter:
97 | sys.stdout.write(cf.GETTING_TIPS)
98 | sys.stdout.flush()
99 |
100 |
101 | def _writeConsole(self):
102 | if self._inter:
103 | sys.stdout.write(cf.GETTING_FLAG)
104 | sys.stdout.flush()
105 |
106 |
107 |
--------------------------------------------------------------------------------
/GuGu/billboard.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | """
3 | 龙虎榜类
4 | Created on 2019/01/11
5 | @author: TabQ
6 | @group : GuGu
7 | @contact: 16621596@qq.com
8 | """
9 |
10 | import time
11 | import re
12 | import pandas as pd
13 | from pandas.compat import StringIO
14 | import lxml.html
15 | from lxml import etree
16 | from base import Base, cf
17 | from utility import Utility
18 |
19 | class BillBoard(Base):
20 | def topList(self, date = None, retry=3, pause=0.001):
21 | """
22 | 获取每日龙虎榜列表
23 | Parameters
24 | --------
25 | date:string
26 | 明细数据日期 format:YYYY-MM-DD 如果为空,返回最近一个交易日的数据
27 | retry : int, 默认 3
28 | 如遇网络等问题重复执行的次数
29 | pause : int, 默认 0
30 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
31 |
32 | Return
33 | ------
34 | DataFrame or List: [{'code':, 'name':, ...}, ...]
35 | code:代码
36 | name :名称
37 | pchange:涨跌幅
38 | amount:龙虎榜成交额(万)
39 | buy:买入额(万)
40 | bratio:占总成交比例
41 | sell:卖出额(万)
42 | sratio :占总成交比例
43 | reason:上榜原因
44 | unscramble: 解读
45 | date :日期
46 | """
47 | self._data = pd.DataFrame()
48 |
49 | if date is None:
50 | if Utility.getHour() < 18:
51 | date = Utility.lastTradeDate()
52 | else:
53 | date = Utility.getToday()
54 | else:
55 | if not Utility.isTradeDay(date):
56 | return None
57 |
58 | for _ in range(retry):
59 | time.sleep(pause)
60 |
61 | try:
62 | # http://data.eastmoney.com/DataCenter_V3/stock2016/TradeDetail/pagesize=200,page=1,sortRule=-1,sortType=,startDate=2019-01-10,endDate=2019-01-10,gpfw=0,js=vardata_tab_1.html
63 | request = self._session.get( cf.LHB_URL % (date, date), timeout=10 )
64 | request.encoding = 'gbk'
65 | text = request.text.split('_1=')[1]
66 | dataDict = Utility.str2Dict(text)
67 |
68 | self._data = pd.DataFrame(dataDict['data'], columns=cf.LHB_TMP_COLS)
69 | self._data.columns = cf.LHB_COLS
70 | self._data['buy'] = self._data['buy'].astype(float)
71 | self._data['sell'] = self._data['sell'].astype(float)
72 | self._data['amount'] = self._data['amount'].astype(float)
73 | self._data['Turnover'] = self._data['Turnover'].astype(float)
74 | self._data['bratio'] = self._data['buy'] / self._data['Turnover']
75 | self._data['sratio'] = self._data['sell'] / self._data['Turnover']
76 | self._data['bratio'] = self._data['bratio'].map(cf.FORMAT)
77 | self._data['sratio'] = self._data['sratio'].map(cf.FORMAT)
78 | self._data['date'] = date
79 | for col in ['amount', 'buy', 'sell']:
80 | self._data[col] = self._data[col].astype(float)
81 | self._data[col] = self._data[col] / 10000
82 | self._data[col] = self._data[col].map(cf.FORMAT)
83 | self._data = self._data.drop('Turnover', axis=1)
84 | except:
85 | pass
86 | else:
87 | return self._result()
88 |
89 | raise IOError(cf.NETWORK_URL_ERROR_MSG)
90 |
91 |
92 | def countTops(self, days=5, retry=3, pause=0.001):
93 | """
94 | 获取个股上榜统计数据
95 | Parameters
96 | --------
97 | days:int
98 | 天数,统计n天以来上榜次数,默认为5天,其余是10、30、60
99 | retry : int, 默认 3
100 | 如遇网络等问题重复执行的次数
101 | pause : int, 默认 0
102 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
103 | Return
104 | ------
105 | DataFrame or List: [{'code':, 'name':, ...}, ...]
106 | code:代码
107 | name:名称
108 | count:上榜次数
109 | bamount:累积购买额(万)
110 | samount:累积卖出额(万)
111 | net:净额(万)
112 | bcount:买入席位数
113 | scount:卖出席位数
114 | """
115 | self._data = pd.DataFrame()
116 |
117 | if Utility.checkLhbInput(days) is True:
118 | self._writeHead()
119 |
120 | # http://vip.stock.finance.sina.com.cn/q/go.php/vLHBData/kind/ggtj/index.phtml?last=5&p=1
121 | self._data = self.__parsePage(kind=cf.LHB_KINDS[0], last=days, column=cf.LHB_GGTJ_COLS, dataArr=pd.DataFrame(), pageNo=1, retry=retry, pause=pause)
122 | self._data['code'] = self._data['code'].map(lambda x: str(x).zfill(6))
123 | if self._data is not None:
124 | self._data = self._data.drop_duplicates('code')
125 |
126 | return self._result()
127 |
128 |
129 | def brokerTops(self, days=5, retry=3, pause=0.001):
130 | """
131 | 获取营业部上榜统计数据
132 | Parameters
133 | --------
134 | days:int
135 | 天数,统计n天以来上榜次数,默认为5天,其余是10、30、60
136 | retry : int, 默认 3
137 | 如遇网络等问题重复执行的次数
138 | pause : int, 默认 0
139 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
140 | Return
141 | ---------
142 | DataFrame or List: [{'broker':, 'count':, ...}, ...]
143 | broker:营业部名称
144 | count:上榜次数
145 | bamount:累积购买额(万)
146 | bcount:买入席位数
147 | samount:累积卖出额(万)
148 | scount:卖出席位数
149 | top3:买入前三股票
150 | """
151 | self._data = pd.DataFrame()
152 |
153 | if Utility.checkLhbInput(days) is True:
154 | self._writeHead()
155 |
156 | # http://vip.stock.finance.sina.com.cn/q/go.php/vLHBData/kind/yytj/index.phtml?last=5&p=1
157 | self._data = self.__parsePage(kind=cf.LHB_KINDS[1], last=days, column=cf.LHB_YYTJ_COLS, dataArr=pd.DataFrame(), pageNo=1, retry=retry, pause=pause)
158 |
159 | return self._result()
160 |
161 |
162 | def instTops(self, days=5, retry=3, pause=0.001):
163 | """
164 | 获取机构席位追踪统计数据
165 | Parameters
166 | --------
167 | days:int
168 | 天数,统计n天以来上榜次数,默认为5天,其余是10、30、60
169 | retry : int, 默认 3
170 | 如遇网络等问题重复执行的次数
171 | pause : int, 默认 0
172 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
173 |
174 | Return
175 | --------
176 | DataFrame or List: [{'code':, 'name':, ...}, ...]
177 | code:代码
178 | name:名称
179 | bamount:累积买入额(万)
180 | bcount:买入次数
181 | samount:累积卖出额(万)
182 | scount:卖出次数
183 | net:净额(万)
184 | """
185 | self._data = pd.DataFrame()
186 |
187 | if Utility.checkLhbInput(days) is True:
188 | self._writeHead()
189 |
190 | # http://vip.stock.finance.sina.com.cn/q/go.php/vLHBData/kind/jgzz/index.phtml?last=5&p=1
191 | self._data = self.__parsePage(kind=cf.LHB_KINDS[2], last=days, column=cf.LHB_JGZZ_COLS, dataArr=pd.DataFrame(), pageNo=1, retry=retry, pause=pause, drop_column=[2,3])
192 | self._data['code'] = self._data['code'].map(lambda x: str(x).zfill(6))
193 |
194 | return self._result()
195 |
196 |
197 | def instDetail(self, retry=3, pause=0.001):
198 | """
199 | 获取最近一个交易日机构席位成交明细统计数据
200 | Parameters
201 | --------
202 | retry : int, 默认 3
203 | 如遇网络等问题重复执行的次数
204 | pause : int, 默认 0
205 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
206 |
207 | Return
208 | ----------
209 | DataFrame or List: [{'code':, 'name':, ...}, ...]
210 | code:股票代码
211 | name:股票名称
212 | date:交易日期
213 | bamount:机构席位买入额(万)
214 | samount:机构席位卖出额(万)
215 | type:类型
216 | """
217 | self._data = pd.DataFrame()
218 |
219 | self._writeHead()
220 |
221 | # http://vip.stock.finance.sina.com.cn/q/go.php/vLHBData/kind/jgmx/index.phtml?last=&p=1
222 | self._data = self.__parsePage(kind=cf.LHB_KINDS[3], last='', column=cf.LHB_JGMX_COLS, dataArr=pd.DataFrame(), pageNo=1, retry=retry, pause=pause)
223 | if len(self._data) > 0:
224 | self._data['code'] = self._data['code'].map(lambda x: str(x).zfill(6))
225 |
226 | return self._result()
227 |
228 |
229 | def __parsePage(self, kind, last, column, dataArr, pageNo=1, retry=3, pause=0.001, drop_column=None):
230 | self._writeConsole()
231 |
232 | for _ in range(retry):
233 | time.sleep(pause)
234 |
235 | try:
236 | request = self._session.get( cf.LHB_SINA_URL % (kind, last, pageNo), timeout=10 )
237 | request.encoding = 'gbk'
238 | html = lxml.html.parse(StringIO(request.text))
239 | res = html.xpath("//table[@id=\"dataTable\"]/tr")
240 | if self._PY3:
241 | sarr = [etree.tostring(node).decode('utf-8') for node in res]
242 | else:
243 | sarr = [etree.tostring(node) for node in res]
244 | sarr = ''.join(sarr)
245 | sarr = '
'%sarr
246 | df = pd.read_html(sarr)[0]
247 | if drop_column is not None:
248 | df = df.drop(drop_column, axis=1)
249 | df.columns = column
250 | dataArr = dataArr.append(df, ignore_index=True)
251 | nextPage = html.xpath('//div[@class=\"pages\"]/a[last()]/@onclick')
252 | if len(nextPage) > 0:
253 | pageNo = re.findall(r'\d+', nextPage[0])[0]
254 | return self.__parsePage(kind, last, column, dataArr, pageNo, retry, pause, drop_column)
255 | else:
256 | return dataArr
257 | except Exception as e:
258 | print(e)
259 |
260 |
261 |
--------------------------------------------------------------------------------
/GuGu/classify.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | """
3 | 股票所属类
4 | Created on 2019/01/10
5 | @author: TabQ
6 | @group : GuGu
7 | @contact: 16621596@qq.com
8 | """
9 | import time
10 | import json
11 | import re
12 | import pandas as pd
13 | from base import Base, cf
14 |
15 | class Classify(Base):
16 | def byIndustry(self, std='sina', retry=3, pause=0.001):
17 | """
18 | 获取行业分类数据
19 | Parameters
20 | ----------
21 | std : string
22 | sina:新浪行业 sw:申万 行业
23 | retry : int, 默认 10
24 | 如遇网络等问题重复执行的次数
25 | pause : int, 默认 0.001
26 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
27 |
28 | Returns
29 | -------
30 | DataFrame or List: [{'code':, 'name':, ...}, ...]
31 | code :股票代码
32 | name :股票名称
33 | c_name :行业名称
34 | """
35 | self._data = pd.DataFrame()
36 |
37 | if std == 'sw':
38 | # http://vip.stock.finance.sina.com.cn/q/view/SwHy.php
39 | df = self.__getTypeData(cf.SINA_INDUSTRY_INDEX_URL % 'SwHy.php')
40 | else:
41 | # http://vip.stock.finance.sina.com.cn/q/view/newSinaHy.php
42 | df = self.__getTypeData(cf.SINA_INDUSTRY_INDEX_URL % 'newSinaHy.php')
43 |
44 | self._writeHead()
45 | for row in df.values:
46 | rowDf = self.__getDetail(row[0], retry, pause)
47 | rowDf['c_name'] = row[1]
48 | self._data = self._data.append(rowDf, ignore_index=True)
49 |
50 | return self._result()
51 |
52 |
53 | def byConcept(self, retry=3, pause=0.001):
54 | """
55 | 获取概念分类数据
56 | Parameters
57 | ----------
58 | retry : int, 默认 3
59 | 如遇网络等问题重复执行的次数
60 | pause : int, 默认 0.001
61 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
62 | Return
63 | --------
64 | DataFrame
65 | code :股票代码
66 | name :股票名称
67 | c_name :概念名称
68 | """
69 | self._data = pd.DataFrame()
70 |
71 | self._writeHead()
72 | # http://money.finance.sina.com.cn/q/view/newFLJK.php?param=class
73 | df = self.__getTypeData( cf.SINA_CONCEPTS_INDEX_URL )
74 |
75 | for row in df.values:
76 | rowDf = self.__getDetail(row[0], retry, pause)
77 | rowDf['c_name'] = row[1]
78 | self._data = self._data.append(rowDf)
79 |
80 | return self._result()
81 |
82 |
83 | def __getTypeData(self, url):
84 | try:
85 | request = self._session.get(url, timeout=10)
86 | request.encoding = 'gbk'
87 | text = request.text.split('=')[1]
88 | dataJson = json.loads(text)
89 | df = pd.DataFrame([[row.split(',')[0], row.split(',')[1]] for row in dataJson.values()], columns=['tag', 'name'])
90 |
91 | return df
92 | except Exception as e:
93 | print(str(e))
94 |
95 | def __getDetail(self, tag, retry=3, pause=0.001):
96 | self._writeConsole()
97 |
98 | for retryCount in range(retry):
99 | time.sleep(pause)
100 |
101 | try:
102 | # http://vip.stock.finance.sina.com.cn/quotes_service/api/json_v2.php/Market_Center.getHQNodeData?page=1&num=1000&sort=symbol&asc=1&node=new_zhhy&symbol=&_s_r_a=page
103 | request = self._session.get( cf.SINA_DATA_DETAIL_URL % tag, timeout=10 )
104 | reg = re.compile(r'\,(.*?)\:')
105 | text = reg.sub(r',"\1":', request.text)
106 | text = text.replace('"{symbol', '{"symbol')
107 | text = text.replace('{symbol', '{"symbol"')
108 | jstr = json.dumps(text)
109 | js = json.loads(jstr)
110 |
111 | df = pd.DataFrame(pd.read_json(js, dtype={'code':object}), columns=cf.FOR_CLASSIFY_B_COLS)
112 |
113 | return df
114 | except:
115 | time.sleep((retryCount+1)*10)
116 |
117 | raise IOError(cf.NETWORK_ERR_MSG)
118 |
119 |
120 |
--------------------------------------------------------------------------------
/GuGu/config.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | """
3 | 地址&配置
4 | Created on 2018/12/26
5 | @author: TabQ
6 | @group : GuGu
7 | @contact: 16621596@qq.com
8 | """
9 |
10 | VERSION = '0.1.0'
11 | HOLIDAY_URL = 'http://timor.tech/api/holiday/info/%s'
12 | K_LABELS = ['D', 'W', 'M']
13 | K_MIN_LABELS = ['5', '15', '30', '60']
14 | K_TYPE = {'D': 'akdaily', 'W': 'akweekly', 'M': 'akmonthly'}
15 | TT_K_TYPE = {'D': 'day', 'W': 'week', 'M': 'month'}
16 | FQ_KEY = ['qfqday', 'hfqday', 'day']
17 | INDEX_LABELS = ['sh', 'sz', 'hs300', 'sz50', 'cyb', 'zxb', 'zx300', 'zh500']
18 | INDEX_LIST = {'sh': 'sh000001', 'sz': 'sz399001', 'hs300': 'sz399300',
19 | 'sz50': 'sh000016', 'zxb': 'sz399005', 'cyb': 'sz399006', 'zx300': 'sz399008', 'zh500':'sh000905'}
20 | P_TYPE = {'http': 'http://', 'ftp': 'ftp://'}
21 | PAGE_NUM = [40, 60, 80, 100]
22 | FORMAT = lambda x: '%.2f' % x
23 | FORMAT4 = lambda x: '%.4f' % x
24 | INDEX_ETF_URL = 'https://www.jisilu.cn/jisiludata/etf.php?rp=25&page=%s'
25 | INDEX_ETF_COLS = ['fund_id', 'fund_nm', 'index_id', 'creation_unit', 'amount', 'unit_total',
26 | 'unit_incr', 'price', 'volume', 'increase_rt', 'estimate_value', 'discount_rt',
27 | 'fund_nav', 'nav_dt', 'index_nm', 'index_increase_rt', 'pe', 'pb']
28 | STOCK_LOF_URL = 'https://www.jisilu.cn/data/lof/stock_lof_list/?rp=25&page=%s'
29 | STOCK_LOF_COLS = ['fund_id', 'fund_nm', 'price', 'increase_rt', 'volume', 'amount',
30 | 'fund_nav', 'nav_dt', 'estimate_value', 'discount_rt', 'stock_ratio',
31 | 'stock_increase_rt', 'apply_fee', 'redeem_fee', 'apply_redeem_status']
32 | INDEX_LOF_URL = 'https://www.jisilu.cn/data/lof/index_lof_list/?rp=25&page=%s'
33 | INDEX_LOF_COLS = ['fund_id', 'fund_nm', 'price', 'increase_rt', 'volume', 'amount',
34 | 'fund_nav', 'nav_dt', 'estimate_value', 'discount_rt', 'index_id', 'index_nm',
35 | 'index_increase_rt', 'apply_fee', 'redeem_fee', 'apply_redeem_status']
36 | RATING_FUNDA_URL = 'https://www.jisilu.cn/data/sfnew/funda_list/?page=%s'
37 | RATING_FUNDA_COLS = ['funda_id', 'funda_name', 'funda_current_price', 'funda_increase_rt', 'funda_volume', 'funda_value',
38 | 'funda_discount_rt', 'funda_coupon', 'funda_coupon_next', 'funda_profit_rt_next', 'funda_index_id',
39 | 'funda_index_name', 'funda_index_increase_rt', 'funda_lower_recalc_rt', 'lower_recalc_profit_rt',
40 | 'fundb_upper_recalc_rt', 'funda_base_est_dis_rt_t1', 'funda_base_est_dis_rt_t2', 'funda_amount',
41 | 'funda_amount_increase', 'abrate', 'next_recalc_dt']
42 | RATING_FUNDB_URL = 'https://www.jisilu.cn/data/sfnew/fundb_list/?page=%s'
43 | RATING_FUNDB_COLS = ['fundb_id', 'fundb_name', 'fundb_base_fund_id', 'funda_id', 'funda_name', 'coupon', 'manage_fee', 'funda_current_price',
44 | 'funda_upper_price', 'funda_lower_price', 'funda_increase_rt', 'fundb_current_price', 'fundb_upper_price',
45 | 'fundb_lower_price', 'fundb_increase_rt', 'fundb_volume', 'fundb_value', 'fundm_value', 'fundb_discount_rt',
46 | 'fundb_price_leverage_rt', 'fundb_net_leverage_rt', 'fundb_capital_rasising_rt', 'fundb_lower_recalc_rt',
47 | 'fundb_upper_recalc_rt', 'b_est_val', 'fundb_index_id', 'fundb_index_name', 'fundb_index_increase_rt',
48 | 'funda_ratio', 'fundb_ratio', 'fundb_base_price', 'fundB_amount', 'fundB_amount_increase', 'abrate']
49 | RATING_FUNDM_URL = 'https://www.jisilu.cn/data/sfnew/fundm_list/?page=%s'
50 | RATING_FUNDM_COLS = ['base_fund_id', 'base_fund_nm', 'market', 'issue_dt', 'manage_fee', 'index_id', 'index_nm', 'lower_recalc_price',
51 | 'a_ratio', 'b_ratio', 'next_recalc_dt', 'fundA_id', 'fundA_nm', 'coupon', 'coupon_next', 'fundB_id', 'fundB_nm',
52 | 'price', 'base_lower_recalc_rt', 'abrate']
53 | CON_BONDS_URL = 'https://www.jisilu.cn/data/cbnew/cb_list/?page=%s'
54 | CON_BONDS_COLS = ['bond_id', 'bond_nm', 'stock_id', 'stock_nm', 'market', 'convert_price', 'convert_dt', 'issue_dt', 'maturity_dt',
55 | 'next_put_dt', 'put_price', 'put_count_days', 'put_total_days', 'redeem_price', 'redeem_price_ratio', 'redeem_count_days',
56 | 'redeem_total_days', 'orig_iss_amt', 'curr_iss_amt', 'rating_cd', 'issuer_rating_cd', 'guarantor', 'active_fl', 'ration_rt',
57 | 'pb', 'sprice', 'sincrease_rt', 'last_time', 'convert_value', 'premium_rt', 'year_left', 'ytm_rt', 'ytm_rt_tax', 'price',
58 | 'increase_rt', 'volume', 'force_redeem_price', 'put_convert_price', 'convert_amt_ratio', 'stock_cd', 'pre_bond_id']
59 | CLOSED_STOCK_FUND_URL = 'https://www.jisilu.cn/data/cf/cf_list/?page=%s'
60 | CLOSED_STOCK_FUND_COLS = ['fund_id', 'fund_nm', 'issue_dt', 'duration', 'last_time', 'price', 'increase_rt', 'volume', 'net_value',
61 | 'nav_dt', 'realtime_estimate_value', 'discount_rt', 'left_year', 'annualize_dscnt_rt', 'quote_incr_rt',
62 | 'nav_incr_rt', 'spread', 'stock_ratio', 'report_dt', 'daily_nav_incr_rt', 'daily_spread']
63 | CLOSED_BOND_FUND_URL = 'https://www.jisilu.cn/jisiludata/CloseBondFund.php?page=%s'
64 | CLOSED_BOND_FUND_COLS = ['fund_id', 'fund_nm', 'maturity_dt', 'left_year', 'est_val', 'discount_rt', 'annual_discount_rt',
65 | 'trade_price', 'increase_rt', 'volume', 'last_time', 'fund_nav', 'last_chg_dt', 'price_incr_rt',
66 | 'stock_ratio', 'bond_ratio', 'report_dt', 'is_outdate']
67 | AH_RATIO_URL = 'https://www.jisilu.cn/data/ha/index2list/?page=%s'
68 | AH_RATIO_COLS = ['a_code', 'stock_name', 'a_price', 'a_increase_rt', 'h_code', 'h_price', 'h_increase_rt', 'last_time',
69 | 'rmb_price', 'hk_currency', 'ha_ratio', 'h_free_shares', 'a_free_shares']
70 | DIVIDEND_RATE_URL = 'https://www.jisilu.cn/data/stock/dividend_rate_list/?page=%s'
71 | DIVIDEND_RATE_COLS = ['stock_id', 'stock_nm', 'dividend_rate', 'dividend_rate2', 'ipo_date', 'price', 'volume', 'increase_rt', 'pe', 'pb',
72 | 'total_value', 'eps_growth_ttm', 'roe', 'revenue_average', 'profit_average', 'roe_average',
73 | 'pb_temperature', 'pe_temperature', 'int_debt_rate', 'cashflow_average', 'dividend_rate_average',
74 | 'dividend_rate5', 'industry_nm', 'active_flg', 'last_time']
75 | HISTORY_TICK_COLUMNS = ['time', 'price', 'change', 'volume', 'amount', 'type']
76 | TODAY_TICK_COLUMNS = ['time', 'price', 'pchange', 'change', 'volume', 'amount', 'type']
77 | DAY_TRADING_COLUMNS = ['code', 'symbol', 'name', 'changepercent',
78 | 'trade', 'open', 'high', 'low', 'settlement', 'volume', 'turnoverratio',
79 | 'amount', 'per', 'pb', 'mktcap', 'nmc']
80 | REPORT_COLS = ['code', 'name', 'eps', 'eps_yoy', 'bvps', 'roe',
81 | 'epcf', 'net_profits', 'profits_yoy', 'distrib', 'report_date']
82 | FORECAST_COLS = ['code', 'name', 'type', 'report_date', 'pre_eps', 'range']
83 | PROFIT_COLS = ['code', 'name', 'roe', 'net_profit_ratio',
84 | 'gross_profit_rate', 'net_profits', 'eps', 'business_income', 'bips']
85 | OPERATION_COLS = ['code', 'name', 'arturnover', 'arturndays', 'inventory_turnover',
86 | 'inventory_days', 'currentasset_turnover', 'currentasset_days']
87 | GROWTH_COLS = ['code', 'name', 'mbrg', 'nprg', 'nav', 'targ', 'epsg', 'seg']
88 | DEBTPAYING_COLS = ['code', 'name', 'currentratio',
89 | 'quickratio', 'cashratio', 'icratio', 'sheqratio', 'adratio']
90 | CASHFLOW_COLS = ['code', 'name', 'cf_sales', 'rateofreturn',
91 | 'cf_nm', 'cf_liabilities', 'cashflowratio']
92 | DAY_PRICE_COLUMNS = ['date', 'open', 'high', 'close', 'low', 'volume', 'price_change', 'p_change',
93 | 'ma5', 'ma10', 'ma20', 'v_ma5', 'v_ma10', 'v_ma20', 'turnover']
94 | INX_DAY_PRICE_COLUMNS = ['date', 'open', 'high', 'close', 'low', 'volume', 'price_change', 'p_change',
95 | 'ma5', 'ma10', 'ma20', 'v_ma5', 'v_ma10', 'v_ma20']
96 | LIVE_DATA_COLS = ['name', 'open', 'pre_close', 'price', 'high', 'low', 'bid', 'ask', 'volume', 'amount',
97 | 'b1_v', 'b1_p', 'b2_v', 'b2_p', 'b3_v', 'b3_p', 'b4_v', 'b4_p', 'b5_v', 'b5_p',
98 | 'a1_v', 'a1_p', 'a2_v', 'a2_p', 'a3_v', 'a3_p', 'a4_v', 'a4_p', 'a5_v', 'a5_p', 'date', 'time', 's']
99 | FOR_CLASSIFY_B_COLS = ['code','name']
100 | FOR_CLASSIFY_W_COLS = ['date','code', 'weight']
101 | FOR_CLASSIFY_W5_COLS = ['date','code', 'name', 'weight']
102 | THE_FIELDS = ['code','symbol','name','changepercent','trade','open','high','low','settlement','volume','turnoverratio']
103 | KLINE_TT_COLS = ['date', 'open', 'close', 'high', 'low', 'volume']
104 | HISTORY_TICKS_URL = 'http://market.finance.sina.com.cn/transHis.php?date=%s&symbol=%s&page=%s'
105 | TODAY_TICKS_PAGE_URL = 'http://vip.stock.finance.sina.com.cn/quotes_service/api/json_v2.php/CN_Transactions.getAllPageTime?date=%s&symbol=%s'
106 | TODAY_TICKS_URL = 'http://vip.stock.finance.sina.com.cn/quotes_service/view/vMS_tradedetail.php?symbol=%s&date=%s&page=%s'
107 | HISTORY_URL = 'http://web.ifzq.gtimg.cn/appstock/app/%skline/get?_var=kline_day%s¶m=%s,%s,%s,%s,640,%s&r=0.%s'
108 | HISTORY_MIN_URL = 'http://ifzq.gtimg.cn/appstock/app/kline/mkline?param=%s,m%s,,640&_var=m%s_today&r=0.%s'
109 | DAY_PRICE_URL = '%sapi.finance.%s/%s/?code=%s&type=last'
110 | LIVE_DATA_URL = 'http://hq.sinajs.cn/rn=%s&list=%s'
111 | DAY_PRICE_MIN_URL = '%sapi.finance.%s/akmin?scode=%s&type=%s'
112 | LATEST_URL = 'http://vip.stock.finance.sina.com.cn/quotes_service/api/json_v2.php/Market_Center.getHQNodeData?num=80&sort=code&asc=0&node=hs_a&symbol=&_s_r_a=page&page=%s'
113 | REPORT_URL = 'http://vip.stock.finance.sina.com.cn/q/go.php/vFinanceAnalyze/kind/mainindex/index.phtml?s_i=&s_a=&s_c=&reportdate=%s&quarter=%s&p=%s&num=%s'
114 | FORECAST_URL = 'http://vip.stock.finance.sina.com.cn/q/go.php/vFinanceAnalyze/kind/performance/index.phtml?s_i=&s_a=&s_c=&s_type=&reportdate=%s&quarter=%s&p=%s&num=%s'
115 | PROFIT_URL = 'http://vip.stock.finance.sina.com.cn/q/go.php/vFinanceAnalyze/kind/profit/index.phtml?s_i=&s_a=&s_c=&reportdate=%s&quarter=%s&p=%s&num=%s'
116 | OPERATION_URL = 'http://vip.stock.finance.sina.com.cn/q/go.php/vFinanceAnalyze/kind/operation/index.phtml?s_i=&s_a=&s_c=&reportdate=%s&quarter=%s&p=%s&num=%s'
117 | GROWTH_URL = 'http://vip.stock.finance.sina.com.cn/q/go.php/vFinanceAnalyze/kind/grow/index.phtml?s_i=&s_a=&s_c=&reportdate=%s&quarter=%s&p=%s&num=%s'
118 | DEBTPAYING_URL = 'http://vip.stock.finance.sina.com.cn/q/go.php/vFinanceAnalyze/kind/debtpaying/index.phtml?s_i=&s_a=&s_c=&reportdate=%s&quarter=%s&p=%s&num=%s'
119 | CASHFLOW_URL = 'http://vip.stock.finance.sina.com.cn/q/go.php/vFinanceAnalyze/kind/cashflow/index.phtml?s_i=&s_a=&s_c=&reportdate=%s&quarter=%s&p=%s&num=%s'
120 | SHIBOR_TYPE ={'Shibor': 'Shibor数据', 'Quote': '报价数据', 'Tendency': 'Shibor均值数据',
121 | 'LPR': 'LPR数据', 'LPR_Tendency': 'LPR均值数据'}
122 | SHIBOR_DATA_URL = 'http://www.shibor.org/shibor/web/html/downLoad.html?nameNew=Historical_%s_Data_%s.xls&downLoadPath=data&nameOld=%s%s.xls&shiborSrc=http://www.shibor.org/shibor/'
123 | ALL_STOCK_PROFILES_URL = 'http://s.askci.com/stock/a/?reportTime=%s&pageNum=%s#QueryCondition'
124 | ALL_STOCK_PROFILES_COLS = ['code', 'name', 'city', 'staff', 'date', 'industry', 'pro_type', 'main']
125 | SINA_CONCEPTS_INDEX_URL = 'http://money.finance.sina.com.cn/q/view/newFLJK.php?param=class'
126 | SINA_INDUSTRY_INDEX_URL = 'http://vip.stock.finance.sina.com.cn/q/view/%s'
127 | SINA_DATA_DETAIL_URL = 'http://vip.stock.finance.sina.com.cn/quotes_service/api/json_v2.php/Market_Center.getHQNodeData?page=1&num=1000&sort=symbol&asc=1&node=%s&symbol=&_s_r_a=page'
128 | INDEX_C_COMM = 'sseportal/ps/zhs/hqjt/csi'
129 | HS300_CLASSIFY_URL_FTP = '%s%s/webdata/%s'
130 | HS300_CLASSIFY_URL_HTTP = '%s%s/%s/%s'
131 | HIST_FQ_URL = '%s%s/corp/go.php/vMS_FuQuanMarketHistory/stockid/%s.phtml?year=%s&jidu=%s'
132 | HIST_INDEX_URL = '%s%s/corp/go.php/vMS_MarketHistory/stockid/%s/type/S.phtml?year=%s&jidu=%s'
133 | HIST_FQ_FACTOR_URL = '%s%s/api/json.php/BasicStockSrv.getStockFuQuanData?symbol=%s&type=hfq'
134 | INDEX_URL = 'http://hq.sinajs.cn/rn=xppzh&list=sh000001,sh000002,sh000003,sh000008,sh000009,sh000010,sh000011,sh000012,sh000016,sh000017,sh000300,sh000905,sz399001,sz399002,sz399003,sz399004,sz399005,sz399006,sz399008,sz399100,sz399101,sz399106,sz399107,sz399108,sz399333,sz399606'
135 | SSEQ_CQ_REF_URL = '%s%s/assortment/stock/list/name'
136 | SINA_DD = 'http://vip.stock.finance.sina.com.cn/quotes_service/view/cn_bill_download.php?symbol=%s&num=60&page=1&sort=ticktime&asc=0&volume=%s&amount=0&type=0&day=%s'
137 | BOX = 'boxOffice'
138 | MOVIE_BOX = '%s%s/%s/GetHourBoxOffice?d=%s'
139 | BOXOFFICE_DAY = '%s%s/%s/GetDayBoxOffice?num=%s&d=%s'
140 | BOXOFFICE_MONTH = '%s%s/%s/getMonthBox?sdate=%s'
141 | BOXOFFICE_CBD = '%s%s/%s/getCBD?pIndex=%s&dt=%s'
142 | SHIBOR_COLS = ['date', 'ON', '1W', '2W', '1M', '3M', '6M', '9M', '1Y']
143 | QUOTE_COLS = ['date', 'bank', 'ON', '1W', '2W', '1M', '3M', '6M', '9M', '1Y']
144 | SHIBOR_MA_COLS = ['date', 'ON_5', 'ON_10', 'ON_20', '1W_5', '1W_10', '1W_20','2W_5', '2W_10', '2W_20',
145 | '1M_5', '1M_10', '1M_20', '3M_5', '3M_10', '3M_20', '6M_5', '6M_10', '6M_20',
146 | '9M_5', '9M_10', '9M_20','1Y_5', '1Y_10', '1Y_20']
147 | LPR_COLS = ['date', '1Y']
148 | LPR_MA_COLS = ['date', '1Y_5', '1Y_10', '1Y_20']
149 | INDEX_HEADER = 'code,name,open,preclose,close,high,low,0,0,volume,amount,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,d,c,3\n'
150 | INDEX_COLS = ['code', 'name', 'change', 'open', 'preclose', 'close', 'high', 'low', 'volume', 'amount']
151 | HIST_FQ_COLS = ['date', 'open', 'high', 'close', 'low', 'volume', 'amount', 'factor']
152 | SINA_DD_COLS = ['code', 'name', 'time', 'price', 'volume', 'preprice', 'type']
153 | GLOBAL_HQ_SYMBOL = 'sh000001,hkHSI,znb_UKX,znb_DAX,znb_INDEXCF,znb_CAC,znb_SMI,znb_FTSEMIB,znb_MADX,znb_OMX,znb_SPX,znb_HEX,znb_OSEAX,znb_ISEQ,znb_AEX,znb_ICEXI,znb_NKY,znb_TWSE,znb_FSSTI,znb_KOSPI,znb_FBMKLCI,znb_SET,znb_JCI,znb_PCOMP,znb_KSE100,znb_SENSEX,znb_VNINDEX,znb_CSEALL,znb_SASEIDX,znb_SPTSX,znb_MEXBOL,znb_IBOV,znb_MERVAL,znb_AS51,znb_NZSE50FG,znb_CASE,znb_JALSH,sz399001,znb_INDU,znb_CCMP'
154 | GLOBAL_HQ_COLS = ['symbol', 'name', 'price', 'chga', 'chgp', 'datetime']
155 | HIST_FQ_FACTOR_COLS = ['code','value']
156 | GETTING_TIPS = '[Progress:]'
157 | GETTING_FLAG = '#'
158 | DATA_INPUT_ERROR_MSG = 'date input error.'
159 | NETWORK_URL_ERROR_MSG = '获取失败,请检查网络和URL'
160 | NETWORK_ERR_MSG = '获取失败,请检查网络和URL;或者您访问的过于频繁,被服务器拦截,请稍后再试'
161 | DATE_CHK_MSG = '年度输入错误:请输入1989年以后的年份数字,格式:YYYY'
162 | DATE_CHK_Q_MSG = '季度输入错误:请输入1、2、3或4数字'
163 | TOP_PARAS_MSG = 'top有误,请输入整数或all.'
164 | LHB_MSG = '周期输入有误,请输入数字5、10、30或60'
165 | TOKEN_F_P = 'tk.csv'
166 | BOX_INPUT_ERR_MSG = '请输入YYYY-MM格式的年月数据'
167 | HOLIDAY_SERVE_ERR = '节假日查询服务出错'
168 | INDEX_SYMBOL = {"399990": "sz399990", "000006": "sh000006", "399998": "sz399998",
169 | "399436": "sz399436", "399678": "sz399678", "399804": "sz399804",
170 | "000104": "sh000104", "000070": "sh000070", "399613": "sz399613",
171 | "399690": "sz399690", "399928": "sz399928", "000928": "sh000928",
172 | "000986": "sh000986", "399806": "sz399806", "000032": "sh000032",
173 | "000005": "sh000005", "399381": "sz399381", "399908": "sz399908",
174 | "000908": "sh000908", "399691": "sz399691", "000139": "sh000139",
175 | "399427": "sz399427", "399248": "sz399248", "000832": "sh000832",
176 | "399901": "sz399901", "399413": "sz399413", "000901": "sh000901",
177 | "000078": "sh000078", "000944": "sh000944", "000025": "sh000025",
178 | "399944": "sz399944", "399307": "sz399307", "000052": "sh000052",
179 | "399680": "sz399680", "399232": "sz399232", "399993": "sz399993",
180 | "000102": "sh000102", "000950": "sh000950", "399950": "sz399950",
181 | "399244": "sz399244", "399925": "sz399925", "000925": "sh000925",
182 | "000003": "sh000003", "000805": "sh000805", "000133": "sh000133",
183 | "399677": "sz399677", "399319": "sz399319", "399397": "sz399397",
184 | "399983": "sz399983", "399654": "sz399654", "399440": "sz399440",
185 | "000043": "sh000043", "000012": "sh000012", "000833": "sh000833",
186 | "000145": "sh000145", "000053": "sh000053", "000013": "sh000013",
187 | "000022": "sh000022", "000094": "sh000094", "399299": "sz399299",
188 | "000101": "sh000101", "399817": "sz399817", "399481": "sz399481",
189 | "399434": "sz399434", "399301": "sz399301", "000029": "sh000029",
190 | "399812": "sz399812", "399441": "sz399441", "000098": "sh000098",
191 | "399557": "sz399557", "000068": "sh000068", "399298": "sz399298",
192 | "399302": "sz399302", "000961": "sh000961", "000959": "sh000959",
193 | "399961": "sz399961", "000126": "sh000126", "000036": "sh000036",
194 | "399305": "sz399305", "000116": "sh000116", "399359": "sz399359",
195 | "399810": "sz399810", "000062": "sh000062", "399618": "sz399618",
196 | "399435": "sz399435", "000149": "sh000149", "000819": "sh000819",
197 | "000020": "sh000020", "000061": "sh000061", "000016": "sh000016",
198 | "000028": "sh000028", "399809": "sz399809", "000999": "sh000999",
199 | "399238": "sz399238", "000100": "sh000100", "399979": "sz399979",
200 | "000979": "sh000979", "399685": "sz399685", "000152": "sh000152",
201 | "000153": "sh000153", "399318": "sz399318", "000853": "sh000853",
202 | "000040": "sh000040", "399693": "sz399693", "000076": "sh000076",
203 | "000017": "sh000017", "000134": "sh000134", "399989": "sz399989",
204 | "000042": "sh000042", "000066": "sh000066", "000008": "sh000008",
205 | "000002": "sh000002", "000001": "sh000001", "000011": "sh000011",
206 | "000031": "sh000031", "399403": "sz399403", "000951": "sh000951",
207 | "399951": "sz399951", "000092": "sh000092", "399234": "sz399234",
208 | "000823": "sh000823", "399986": "sz399986", "399647": "sz399647",
209 | "000050": "sh000050", "000073": "sh000073", "399357": "sz399357",
210 | "000940": "sh000940", "000107": "sh000107", "000048": "sh000048",
211 | "399411": "sz399411", "399366": "sz399366", "399373": "sz399373",
212 | "000015": "sh000015", "000021": "sh000021", "000151": "sh000151",
213 | "000851": "sh000851", "000058": "sh000058", "399404": "sz399404",
214 | "399102": "sz399102", "399431": "sz399431", "399971": "sz399971",
215 | "000125": "sh000125", "000069": "sh000069", "000063": "sh000063",
216 | "399395": "sz399395", "000038": "sh000038", "399240": "sz399240",
217 | "399903": "sz399903", "000989": "sh000989", "399321": "sz399321",
218 | "399675": "sz399675", "399235": "sz399235", "000057": "sh000057",
219 | "000056": "sh000056", "000903": "sh000903", "399310": "sz399310",
220 | "000004": "sh000004", "000019": "sh000019", "399919": "sz399919",
221 | "000974": "sh000974", "000919": "sh000919", "399635": "sz399635",
222 | "399663": "sz399663", "399106": "sz399106", "399107": "sz399107",
223 | "399555": "sz399555", "000090": "sh000090", "000155": "sh000155",
224 | "000060": "sh000060", "399636": "sz399636", "000816": "sh000816",
225 | "000010": "sh000010", "399671": "sz399671", "000035": "sh000035",
226 | "399352": "sz399352", "399683": "sz399683", "399554": "sz399554",
227 | "399409": "sz399409", "000018": "sh000018", "399101": "sz399101",
228 | "000992": "sh000992", "399416": "sz399416", "399918": "sz399918",
229 | "399379": "sz399379", "399674": "sz399674", "399239": "sz399239",
230 | "399384": "sz399384", "399367": "sz399367", "000918": "sh000918",
231 | "000914": "sh000914", "399914": "sz399914", "000054": "sh000054",
232 | "000806": "sh000806", "399619": "sz399619", "399015": "sz399015",
233 | "399393": "sz399393", "399313": "sz399313", "399231": "sz399231",
234 | "000846": "sh000846", "000854": "sh000854", "399010": "sz399010",
235 | "399666": "sz399666", "399387": "sz399387", "399399": "sz399399",
236 | "000026": "sh000026", "399934": "sz399934", "000150": "sh000150",
237 | "000934": "sh000934", "399317": "sz399317", "000138": "sh000138",
238 | "399371": "sz399371", "399394": "sz399394", "399659": "sz399659",
239 | "399665": "sz399665", "399931": "sz399931", "000161": "sh000161",
240 | "399380": "sz399380", "000931": "sh000931", "399704": "sz399704",
241 | "399616": "sz399616", "000817": "sh000817", "399303": "sz399303",
242 | "399629": "sz399629", "399624": "sz399624", "399009": "sz399009",
243 | "399233": "sz399233", "399103": "sz399103", "399242": "sz399242",
244 | "399627": "sz399627", "000971": "sh000971", "399679": "sz399679",
245 | "399912": "sz399912", "000982": "sh000982", "399668": "sz399668",
246 | "000096": "sh000096", "399982": "sz399982", "000849": "sh000849",
247 | "000148": "sh000148", "399364": "sz399364", "000912": "sh000912",
248 | "000129": "sh000129", "000055": "sh000055", "000047": "sh000047", "399355": "sz399355", "399622": "sz399622", "000033": "sh000033", "399640": "sz399640", "000852": "sh000852", "399966": "sz399966", "399615": "sz399615", "399802": "sz399802", "399602": "sz399602", "000105": "sh000105", "399660": "sz399660", "399672": "sz399672",
249 | "399913": "sz399913", "399420": "sz399420", "000159": "sh000159", "399314": "sz399314", "399652": "sz399652",
250 | "399369": "sz399369", "000913": "sh000913", "000065": "sh000065",
251 | "000808": "sh000808", "399386": "sz399386", "399100": "sz399100",
252 | "000997": "sh000997", "000990": "sh000990", "000093": "sh000093", "399637": "sz399637", "399439": "sz399439", "399306": "sz399306", "000855": "sh000855", "000123": "sh000123", "399623": "sz399623",
253 | "399312": "sz399312", "399249": "sz399249", "399311": "sz399311", "399975": "sz399975", "399356": "sz399356",
254 | "399400": "sz399400", "399676": "sz399676", "000136": "sh000136", "399361": "sz399361", "399974": "sz399974", "399995": "sz399995", "399316": "sz399316", "399701": "sz399701", "000300": "sh000300", "000030": "sh000030", "000976": "sh000976", "399686": "sz399686", "399108": "sz399108", "399374": "sz399374",
255 | "000906": "sh000906", "399707": "sz399707", "000064": "sh000064", "399633": "sz399633", "399300": "sz399300", "399628": "sz399628", "399398": "sz399398", "000034": "sh000034",
256 | "399644": "sz399644", "399905": "sz399905", "399626": "sz399626",
257 | "399625": "sz399625", "000978": "sh000978", "399664": "sz399664", "399682": "sz399682", "399322": "sz399322", "000158": "sh000158", "000842": "sh000842", "399550": "sz399550", "399423": "sz399423", "399978": "sz399978", "399996": "sz399996", "000905": "sh000905",
258 | "000007": "sh000007", "000827": "sh000827", "399655": "sz399655", "399401": "sz399401", "399650": "sz399650", "000963": "sh000963", "399661": "sz399661", "399922": "sz399922", "000091": "sh000091", "399375": "sz399375", "000922": "sh000922", "399702": "sz399702", "399963": "sz399963", "399011": "sz399011", "399012": "sz399012",
259 | "399383": "sz399383", "399657": "sz399657", "399910": "sz399910", "399351": "sz399351", "000910": "sh000910", "000051": "sh000051", "399376": "sz399376", "399639": "sz399639", "000821": "sh000821", "399360": "sz399360", "399604": "sz399604", "399315": "sz399315", "399658": "sz399658", "000135": "sh000135",
260 | "000059": "sh000059", "399006": "sz399006",
261 | "399320": "sz399320", "000991": "sh000991", "399606": "sz399606",
262 | "399428": "sz399428", "399406": "sz399406", "399630": "sz399630", "000802": "sh000802", "399803": "sz399803", "000071": "sh000071", "399358": "sz399358",
263 | "399013": "sz399013", "399385": "sz399385", "399008": "sz399008", "399649": "sz399649",
264 | "399673": "sz399673", "399418": "sz399418", "399370": "sz399370", "000814": "sh000814",
265 | "399002": "sz399002", "399814": "sz399814", "399641": "sz399641", "399001": "sz399001",
266 | "399662": "sz399662", "399706": "sz399706", "399932": "sz399932", "000095": "sh000095", "000932": "sh000932", "399965": "sz399965", "399363": "sz399363", "399354": "sz399354", "399638": "sz399638", "399648": "sz399648", "399608": "sz399608", "000939": "sh000939", "399939": "sz399939", "399365": "sz399365", "399382": "sz399382", "399631": "sz399631", "399612": "sz399612", "399611": "sz399611", "399645": "sz399645",
267 | "399324": "sz399324", "399552": "sz399552", "000858": "sh000858", "000045": "sh000045",
268 | "000121": "sh000121", "399703": "sz399703", "399003": "sz399003",
269 | "399348": "sz399348", "399389": "sz399389", "399007": "sz399007", "399391": "sz399391", "000973": "sh000973",
270 | "000984": "sh000984", "000969": "sh000969", "000952": "sh000952", "399332": "sz399332", "399952": "sz399952", "399553": "sz399553", "000856": "sh000856",
271 | "399969": "sz399969", "399643": "sz399643", "399402": "sz399402", "399372": "sz399372", "399632": "sz399632", "399344": "sz399344", "399808": "sz399808", "399620": "sz399620", "000103": "sh000103", "399911": "sz399911", "000993": "sh000993", "000983": "sh000983", "399687": "sz399687", "399933": "sz399933", "000933": "sh000933", "399437": "sz399437", "399433": "sz399433", "000046": "sh000046", "000911": "sh000911", "000114": "sh000114", "000049": "sh000049", "399392": "sz399392", "399653": "sz399653", "000975": "sh000975", "000044": "sh000044", "399378": "sz399378", "000828": "sh000828", "399634": "sz399634",
272 | "399005": "sz399005", "000162": "sh000162", "399333": "sz399333", "000122": "sh000122", "399646": "sz399646", "000077": "sh000077", "000074": "sh000074", "399656": "sz399656", "399396": "sz399396", "399415": "sz399415", "399408": "sz399408", "000115": "sh000115", "000987": "sh000987", "399362": "sz399362", "000841": "sh000841", "000141": "sh000141", "000120": "sh000120", "399992": "sz399992", "000807": "sh000807", "399350": "sz399350", "000009": "sh000009", "000998": "sh000998", "399390": "sz399390", "399405": "sz399405", "000099": "sh000099", "399337": "sz399337", "000142": "sh000142", "399419": "sz399419", "399407": "sz399407", "000909": "sh000909", "000119": "sh000119", "399909": "sz399909", "399805": "sz399805", "000996": "sh000996", "000847": "sh000847", "000130": "sh000130", "399377": "sz399377", "399388": "sz399388", "399610": "sz399610", "000958": "sh000958",
273 | "399958": "sz399958", "000075": "sh000075", "399346": "sz399346", "000147": "sh000147", "000132": "sh000132", "000108": "sh000108", "399642": "sz399642", "000977": "sh000977", "399689": "sz399689", "399335": "sz399335", "399977": "sz399977", "399972": "sz399972", "399970": "sz399970", "399004": "sz399004", "399341": "sz399341", "399330": "sz399330", "399917": "sz399917", "000160": "sh000160", "399432": "sz399432", "399429": "sz399429", "000917": "sh000917",
274 | "000128": "sh000128", "000067": "sh000067", "000079": "sh000079", "399236": "sz399236", "399994": "sz399994", "399237": "sz399237", "000966": "sh000966", "000957": "sh000957", "399328": "sz399328",
275 | "399353": "sz399353", "399957": "sz399957", "399412": "sz399412", "000904": "sh000904", "399904": "sz399904", "399410": "sz399410", "000027": "sh000027", "399667": "sz399667", "000857": "sh000857",
276 | "000131": "sh000131", "000964": "sh000964", "399339": "sz399339", "399964": "sz399964", "399991": "sz399991", "399417": "sz399417", "000146": "sh000146", "399551": "sz399551", "000137": "sh000137", "000118": "sh000118", "399976": "sz399976", "000109": "sh000109", "399681": "sz399681", "399438": "sz399438", "000117": "sh000117", "399614": "sz399614", "399669": "sz399669", "000111": "sh000111", "399670": "sz399670", "000097": "sh000097", "000106": "sh000106", "000039": "sh000039", "399935": "sz399935", "000935": "sh000935", "399813": "sz399813", "000037": "sh000037", "399811": "sz399811", "399705": "sz399705", "399556": "sz399556", "000113": "sh000113", "000072": "sh000072", "399651": "sz399651", "399617": "sz399617", "399684": "sz399684", "000041": "sh000041", "399807": "sz399807", "399959": "sz399959", "399967": "sz399967", "399326": "sz399326", "399688": "sz399688", "399368": "sz399368", "399241": "sz399241", "399696": "sz399696", "000850": "sh000850", "000110": "sh000110", "399621": "sz399621", "399243": "sz399243",
277 | "399973": "sz399973", "399987": "sz399987", "000112": "sh000112", "399997": "sz399997",
278 | "hkHSI":"hkHSI"}
279 | DP_163_URL = 'http://quotes.money.163.com/data/caibao/fpyg.html?reportdate=%s&sort=declaredate&order=desc&page=%s'
280 | DP_163_COLS = ['code', 'name', 'year', 'plan', 'report_date']
281 | RL_URL = 'http://datainterface.eastmoney.com/EM_DataCenter/JS.aspx?type=FD&sty=BST&st=3&sr=true&fd=%s&stat=%s'
282 | RL_COLS = ['code', 'name', 'date', 'count', 'ratio']
283 | QUARTS_DIC = {'1':('%s-12-31', '%s-03-31'), '2':('%s-03-31', '%s-06-30'), '3':('%s-06-30', '%s-09-30'), '4':('%s-9-30', '%s-12-31')}
284 | FUND_HOLDS_URL = 'http://quotes.money.163.com/hs/marketdata/service/jjcgph.php?host=/hs/marketdata/service/jjcgph.php&page=%s&query=start:%s;end:%s&order=desc&count=60&type=query&req=%s'
285 | FUND_HOLDS_COLS = ['count', 'clast', 'date', 'ratio', 'amount', 'nums','nlast', 'name', 'code']
286 | NEW_STOCKS_URL = 'http://vip.stock.finance.sina.com.cn/corp/view/vRPD_NewStockIssue.php?page=%s&cngem=0&orderBy=NetDate&orderType=desc'
287 | NEW_STOCKS_COLS = ['code', 'xcode', 'name', 'ipo_date', 'issue_date', 'amount', 'markets', 'price', 'pe', 'limit', 'funds', 'ballot']
288 |
289 | MAR_URL = "http://dcfm.eastmoney.com//EM_MutiSvcExpandInterface/api/js/get?token=70f12f2f4f091e459a279469fe49eca5&st=tdate&sr=-1&p=%s&ps=50&js=var UYirVWSV={pages:(tp),data: (x)}&type=RZRQ_HSTOTAL_NJ&filter=(market='%s')&mk_time=1&rt=%s"
290 | MAR_COLS = ['tdate', 'close', 'zdf', 'rzye', 'rzyezb', 'rzmre', 'rzche', 'rzjmre', 'rqye', 'rqyl', 'rqmcl', 'rqchl', 'rqjmcl', 'rzrqye', 'rzrqyecz']
291 | MAR_BOTH_DETAIL = "http://dcfm.eastmoney.com/em_mutisvcexpandinterface/api/js/get?type=RZRQ_DETAIL_NJ&token=70f12f2f4f091e459a279469fe49eca5&filter=(tdate='%sT00:00:00')&st=rzjmre&sr=-1&p=%s&ps=50&js=var nZxTWeXw={pages:(tp),data:(x)}&type=RZRQ_DETAIL_NJ&time=1&rt=%s"
292 | MAR_DET_All_COLS = ['scode', 'sname', 'rzye', 'rzyezb', 'rzmre', 'rzche', 'rzjmre', 'rqye', 'rqyl', 'rqmcl', 'rqchl', 'rqjmcl', 'rzrqye', 'rzrqyecz']
293 | MAR_TOTAL_URL = 'http://dcfm.eastmoney.com//EM_MutiSvcExpandInterface/api/js/get?token=70f12f2f4f091e459a279469fe49eca5&st=tdate&sr=-1&p=%s&ps=50&js=var BKNgVufZ={pages:(tp),data:(x)}&type=RZRQ_LSTOTAL_NJ&mk_time=1&rt=%s'
294 | MAR_TOTAL_COLS = ['tdate', 'close', 'zdf', 'rzye', 'rzyezb', 'rzmre', 'rzche', 'rzjmre', 'rqye', 'rqyl', 'rqmcl', 'rqchl', 'rqjmcl', 'rzrqye', 'rzrqyecz']
295 |
296 | MACRO_URL = 'http://money.finance.sina.com.cn/mac/api/jsonp.php/SINAREMOTECALLCALLBACK%s/MacPage_Service.get_pagedata?cate=%s&event=%s&from=0&num=%s&condition=&_=%s'
297 | GDP_YEAR_COLS = ['year','gdp','pc_gdp','gnp','pi','si','industry','cons_industry','ti','trans_industry','lbdy']
298 | GDP_QUARTER_COLS = ['quarter','gdp','gdp_yoy','pi','pi_yoy','si','si_yoy','ti','ti_yoy']
299 | GDP_FOR_COLS = ['year','cons_to','cons_rate','asset_to','asset_rate','goods_to','goods_rate']
300 | GDP_PULL_COLS = ['year','gdp_yoy','pi','si','industry','ti']
301 | GDP_CONTRIB_COLS = ['year','gdp_yoy','pi','si','industry','ti']
302 | CPI_COLS = ['month','cpi']
303 | PPI_COLS = ['month','ppiip','ppi','qm','rmi','pi','cg','food','clothing','roeu','dcg']
304 | DEPOSIT_COLS = ['date','deposit_type','rate']
305 | LOAN_COLS = ['date','loan_type','rate']
306 | RRR_COLS = ['date','before','now','changed']
307 | MONEY_SUPPLY_COLS = ['month','m2','m2_yoy','m1','m1_yoy','m0','m0_yoy','cd','cd_yoy','qm','qm_yoy','ftd','ftd_yoy','sd','sd_yoy','rests','rests_yoy']
308 | MONEY_SUPPLY_BLA_COLS = ['year','m2','m1','m0','cd','qm','ftd','sd','rests']
309 |
310 | TERMINATED_URL = '%s%s/%s?jsonCallBack=jsonpCallback%s&isPagination=true&sqlId=COMMON_SSE_ZQPZ_GPLB_MCJS_ZZSSGGJBXX_L&pageHelp.pageSize=50&_=%s'
311 | TERMINATED_T_COLS = ['COMPANY_CODE', 'COMPANY_ABBR', 'LISTING_DATE', 'CHANGE_DATE']
312 | TERMINATED_COLS = ['code', 'name', 'oDate', 'tDate']
313 |
314 | LHB_URL = 'http://data.eastmoney.com/DataCenter_V3/stock2016/TradeDetail/pagesize=200,page=1,sortRule=-1,sortType=,startDate=%s,endDate=%s,gpfw=0,js=vardata_tab_1.html'
315 | LHB_TMP_COLS = ['SCode', 'SName', 'Chgradio', 'ZeMoney', 'Bmoney', 'Smoney', 'Ctypedes', 'Turnover', 'JD']
316 | LHB_COLS = ['code', 'name', 'pchange', 'amount', 'buy', 'sell', 'reason', 'Turnover', 'unscramble']
317 | LHB_SINA_URL = 'http://vip.stock.finance.sina.com.cn/q/go.php/vLHBData/kind/%s/index.phtml?last=%s&p=%s'
318 | LHB_KINDS = ['ggtj', 'yytj', 'jgzz', 'jgmx']
319 | LHB_GGTJ_COLS = ['code', 'name', 'count', 'bamount', 'samount', 'net', 'bcount', 'scount']
320 | LHB_YYTJ_COLS = ['broker', 'count', 'bamount', 'bcount', 'samount', 'scount', 'top3']
321 | LHB_JGZZ_COLS = ['code', 'name', 'bamount', 'bcount', 'samount', 'scount', 'net']
322 | LHB_JGMX_COLS = ['code', 'name', 'date', 'bamount', 'samount', 'type']
323 |
324 | XQ_TOPICS_URL = 'https://xueqiu.com/v4/statuses/public_timeline_by_category.json?since_id=-1&max_id=%d&count=15&category=-1'
325 | XQ_TOPICS_COLS = ['title', 'description', 'target', 'screen_name', 'followers_count', 'source', 'reply_count', 'retweet_count', 'view_count', 'created_at', 'column']
326 | XQ_NEWS_URL = 'https://xueqiu.com/v4/statuses/user_timeline.json?page=%d&user_id=5124430882'
327 | XQ_NEWS_COLS = ['description', 'text', 'source', 'created_at', 'retweet_count', 'reply_count', 'fav_count', 'view_count',
328 | 'reward_count', 'reward_amount', 'reward_user_count', 'talk_count', 'like_count', 'type', 'target', 'timeBefore']
329 | XQ_HOT_COMMENTS_URL = 'https://xueqiu.com/statuses/search.json?count=10&comment=0&symbol=%s&hl=0&source=all&sort=alpha&page=%d&q='
330 | XQ_HOT_COMMENTS_COLS = ['user_id', 'text', 'created_at', 'retweet_count', 'reply_count', 'fav_count', 'description',
331 | 'screen_name', 'friends_count', 'followers_count', 'target', 'view_count', 'reward_count', 'reward_user_count',
332 | 'like_count', 'source']
333 |
334 |
--------------------------------------------------------------------------------
/GuGu/lowriskintarb.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | """
3 | 低风险及套利类
4 | Created on 2019/01/30
5 | @author: TabQ
6 | @group : GuGu
7 | @contact: 16621596@qq.com
8 | """
9 |
10 | import re
11 | import json
12 | import pandas as pd
13 | import numpy as np
14 | from base import Base, cf
15 |
16 | class LowRiskIntArb(Base):
17 | def ratingFundA(self):
18 | """
19 | 分级基金A及其相关数据
20 | return
21 | ------
22 | DataFrame or List: [{'funda_id':, 'funda_name':, ...}, ...]
23 | funda_id: 分级A代码
24 | funda_name: 分级A名称
25 | funda_current_price: 现价
26 | funda_increase_rt: 涨幅(%)
27 | funda_volume: 成交额
28 | funda_value: 净值
29 | funda_discount_rt: 折价率(%)
30 | funda_coupon: 本期利率
31 | funda_coupon_next: 下期利率
32 | funda_profit_rt_next: 修正收益率(%)
33 | funda_index_id: 参考指数代码
34 | funda_index_name: 参考指数名称
35 | funda_index_increase_rt: 指数涨幅(%)
36 | funda_lower_recalc_rt: 下折母基需跌(%)
37 | lower_recalc_profit_rt: 理论下折收益(%)
38 | fundb_upper_recalc_rt: 上折母基需涨(%)
39 | funda_base_est_dis_rt_t1: T-1溢价率(%)
40 | funda_base_est_dis_rt_t2: T-2溢价率(%)
41 | funda_amount: A份额(万份)
42 | funda_amount_increase: A新增(万份)
43 | abrate: A:B
44 | next_recalc_dt: 下次定折日期
45 | """
46 | self._data = pd.DataFrame()
47 |
48 | self._data = self.__parsePage(cf.RATING_FUNDA_URL, cf.RATING_FUNDA_COLS)
49 | self._data[self._data=="-"] = np.NaN
50 | self._data['next_recalc_dt'] = self._data['next_recalc_dt'].map(self.__nextRecalcDt)
51 | for col in ['funda_current_price', 'funda_increase_rt', 'funda_volume', 'funda_value',
52 | 'funda_discount_rt', 'funda_coupon', 'funda_coupon_next', 'funda_profit_rt_next',
53 | 'funda_index_increase_rt', 'funda_lower_recalc_rt', 'lower_recalc_profit_rt',
54 | 'fundb_upper_recalc_rt', 'funda_base_est_dis_rt_t1', 'funda_base_est_dis_rt_t2',
55 | 'funda_amount_increase']:
56 | self._data[col] = self._data[col].astype(float)
57 |
58 | return self._result()
59 |
60 |
61 | def __nextRecalcDt(self, x):
62 | pattern = re.compile(r'(\d{4}-\d{2}-\d{2})')
63 |
64 | return re.sub(pattern, r'\1', x)
65 |
66 |
67 | def ratingFundB(self):
68 | """
69 | 分级基金A及其相关数据
70 | return
71 | ------
72 | DataFrame or List: [{'fundb_id':, 'fundb_name':, ...}, ...]
73 | fundb_id: 分级B代码
74 | fundb_name: 分级B名称
75 | fundb_base_fund_id: 对应母基代码
76 | funda_id: 分级A代码
77 | funda_name: 分级A名称
78 | coupon: 优惠
79 | manage_fee: 管理费
80 | funda_current_price: 分级A现价
81 | funda_upper_price: 分级A最高价
82 | funda_lower_price: 分级A最低价
83 | funda_increase_rt: 分级A增长率(%)
84 | fundb_current_price: 分级B现价
85 | fundb_upper_price: 分级B最高价
86 | fundb_lower_price: 分级B最低价
87 | fundb_increase_rt: 分级B增长率(%)
88 | fundb_volume: 分级B成交额(万元)
89 | fundb_value: 分级B净值
90 | fundm_value: 母基净值
91 | fundb_discount_rt: 分级B溢价率(%)
92 | fundb_price_leverage_rt: 分级B价格杠杆
93 | fundb_net_leverage_rt: 分级B净值杠杆
94 | fundb_capital_rasising_rt: 分级B融资成本(%)
95 | fundb_lower_recalc_rt: 下折母基需跌(%)
96 | fundb_upper_recalc_rt: 上折母基需涨(%)
97 | b_est_val: 估值
98 | fundb_index_id: 参考指数代码
99 | fundb_index_name: 参考指数名称
100 | fundb_index_increase_rt: 参考指数涨幅(%)
101 | funda_ratio: 分级A占比
102 | fundb_ratio: 分级B占比
103 | fundb_base_price: 分级B基础价格
104 | fundB_amount: B份额(万份)
105 | fundB_amount_increase: B新增份额(万份)
106 | abrate: A:B
107 | """
108 | self._data = pd.DataFrame()
109 |
110 | self._data = self.__parsePage(cf.RATING_FUNDB_URL, cf.RATING_FUNDB_COLS)
111 | self._data[self._data=="-"] = np.NaN
112 | for col in ['coupon', 'manage_fee', 'funda_current_price', 'funda_upper_price', 'funda_lower_price',
113 | 'funda_increase_rt', 'fundb_current_price', 'fundb_upper_price', 'fundb_lower_price',
114 | 'fundb_increase_rt', 'fundb_volume', 'fundb_value', 'fundm_value', 'fundb_discount_rt',
115 | 'fundb_price_leverage_rt', 'fundb_net_leverage_rt', 'fundb_capital_rasising_rt',
116 | 'fundb_lower_recalc_rt', 'fundb_upper_recalc_rt', 'b_est_val', 'fundb_index_increase_rt',
117 | 'fundb_base_price', 'fundB_amount', 'fundB_amount_increase']:
118 | self._data[col] = self._data[col].astype(float)
119 |
120 | return self._result()
121 |
122 |
123 | def ratingFundM(self):
124 | """
125 | 分级基金A及其相关数据
126 | return
127 | ------
128 | DataFrame or List: [{}]
129 | base_fund_id: 母基代码
130 | base_fund_nm: 母基名称
131 | market: 所属市场
132 | issue_dt: 创立日期
133 | manage_fee: 管理费
134 | index_id: 跟踪指数代码
135 | index_nm: 跟踪指数名称
136 | lower_recalc_price: 下折
137 | a_ratio: A占比
138 | b_ratio: B占比
139 | next_recalc_dt: 下次定折
140 | fundA_id: A基代码
141 | fundA_nm: A基名称
142 | coupon: 本期利率
143 | coupon_next: 下期利率
144 | fundB_id: B基代码
145 | fundB_nm: B基名称
146 | price: 母基净值
147 | base_lower_recalc_rt: 下折需跌(%)
148 | abrate: A:B
149 | """
150 | self._data = pd.DataFrame()
151 |
152 | self._data = self.__parsePage(cf.RATING_FUNDM_URL, cf.RATING_FUNDM_COLS)
153 | self._data[self._data=="-"] = np.NaN
154 | for col in ['manage_fee', 'lower_recalc_price', 'a_ratio', 'b_ratio', 'coupon', 'coupon_next',
155 | 'price', 'base_lower_recalc_rt']:
156 | self._data[col] = self._data[col].astype(float)
157 |
158 | return self._result()
159 |
160 |
161 | def conBonds(self):
162 | """
163 | 可转债及其相关数据
164 | return
165 | ------
166 | DataFrame or List: [{'bond_id':, 'bond_nm':, ...}, ...]
167 | bond_id: 代码
168 | bond_nm: 名称
169 | stock_id: 正股全代码
170 | stock_nm: 正股名称
171 | market: 所属市场
172 | convert_price: 转股价
173 | convert_dt: 转股起始日
174 | issue_dt: 创立日期
175 | maturity_dt: 到期日
176 | next_put_dt: 回售起始日
177 | put_price: 回售价
178 | put_count_days: 回售计算天数
179 | put_total_days: 回售总天数
180 | redeem_price: 赎回价
181 | redeem_price_ratio: 赎回率
182 | redeem_count_days: 赎回计算天数
183 | redeem_total_days: 赎回总天数
184 | orig_iss_amt: 发行规模(亿)
185 | curr_iss_amt: 剩余规模(亿)
186 | rating_cd: 债券评级
187 | issuer_rating_cd: 主体评级
188 | guarantor: 担保
189 | active_fl: 活跃标志
190 | ration_rt: 股东配售率(%)
191 | pb: 市净率
192 | sprice: 正股价
193 | sincrease_rt: 正股涨跌(%)
194 | last_time: 最后时间
195 | convert_value: 转股价值
196 | premium_rt: 溢价率(%)
197 | year_left: 剩余年限
198 | ytm_rt: 到期税前收益(%)
199 | ytm_rt_tax: 到期税后收益(%)
200 | price: 现价
201 | increase_rt: 涨跌幅(%)
202 | volume: 成交额(万元)
203 | force_redeem_price: 强赎触发价
204 | put_convert_price: 回售触发价
205 | convert_amt_ratio: 转债占比
206 | stock_cd: 正股简码
207 | pre_bond_id: 转债全码
208 | """
209 | self._data = pd.DataFrame()
210 |
211 | self._data = self.__parsePage(cf.CON_BONDS_URL, cf.CON_BONDS_COLS)
212 | self._data[self._data=="-"] = np.NaN
213 | for col in ['convert_price', 'put_price', 'redeem_price', 'redeem_price_ratio', 'orig_iss_amt',
214 | 'curr_iss_amt', 'ration_rt', 'pb', 'sprice', 'sincrease_rt', 'convert_value', 'premium_rt',
215 | 'year_left', 'ytm_rt', 'ytm_rt_tax', 'price', 'increase_rt', 'volume', 'force_redeem_price',
216 | 'put_convert_price', 'convert_amt_ratio']:
217 | self._data[col] = self._data[col].astype(float)
218 |
219 | return self._result()
220 |
221 |
222 | def closedStockFund(self):
223 | """
224 | 封闭股基及其相关数据
225 | return
226 | ------
227 | DataFrame or List: [{'fund_id':, 'fund_nm':, ...}, ...]
228 | fund_id: 代码
229 | fund_nm: 名称
230 | issue_dt: 创立日期
231 | duration: 持续时间
232 | last_time: 最后时间
233 | price: 现价
234 | increase_rt: 涨幅(%)
235 | volume: 成交金额(万)
236 | net_value: 净值
237 | nav_dt: 净值日期
238 | realtime_estimate_value: 最近估值
239 | discount_rt: 折价率(%)
240 | left_year: 剩余年限
241 | annualize_dscnt_rt: 年化折价率(%)
242 | quote_incr_rt: 周价增(%)
243 | nav_incr_rt: 周净增(%)
244 | spread: 净价差(%)
245 | stock_ratio: 股票占比(%)
246 | report_dt: 报告日期
247 | daily_nav_incr_rt: 当日净增(%)
248 | daily_spread: 日净价差(%)
249 | """
250 | self._data = pd.DataFrame()
251 |
252 | self._data = self.__parsePage(cf.CLOSED_STOCK_FUND_URL, cf.CLOSED_STOCK_FUND_COLS)
253 | self._data[self._data=="-"] = np.NaN
254 | for col in ['price', 'increase_rt', 'volume', 'net_value', 'realtime_estimate_value', 'discount_rt',
255 | 'left_year', 'annualize_dscnt_rt', 'quote_incr_rt', 'nav_incr_rt', 'spread', 'stock_ratio',
256 | 'daily_nav_incr_rt', 'daily_spread']:
257 | self._data[col] = self._data[col].astype(float)
258 |
259 | return self._result()
260 |
261 |
262 | def closedBondFund(self):
263 | """
264 | 封闭债基及其相关数据
265 | return
266 | ------
267 | DataFrame or List: [{'fund_id':, 'fund_nm':, ...}, ...]
268 | fund_id: 代码
269 | fund_nm: 名称
270 | maturity_dt: 到期日期
271 | left_year: 剩余年限
272 | est_val: 最近估值
273 | discount_rt: 折价率(%)
274 | annual_discount_rt: 年化折价率(%)
275 | trade_price: 现价
276 | increase_rt: 涨幅(%)
277 | volume: 成交金额
278 | last_time: 最后时间
279 | fund_nav: 最近净值
280 | last_chg_dt: 净值日期
281 | price_incr_rt: 净值日增(%)
282 | stock_ratio: 股票比例
283 | bond_ratio: 债券比例
284 | report_dt: 报告日期
285 | is_outdate: 是否超期
286 | """
287 | self._data = pd.DataFrame()
288 |
289 | self._data = self.__parsePage(cf.CLOSED_BOND_FUND_URL, cf.CLOSED_BOND_FUND_COLS)
290 | self._data[self._data=="-"] = np.NaN
291 | for col in ['left_year', 'est_val', 'discount_rt', 'annual_discount_rt', 'trade_price',
292 | 'increase_rt', 'volume', 'fund_nav', 'price_incr_rt', 'stock_ratio', 'bond_ratio']:
293 | self._data[col] = self._data[col].astype(float)
294 |
295 | return self._result()
296 |
297 |
298 | def AHRatio(self):
299 | """
300 | A/H比价
301 | return
302 | ------
303 | DataFrame or List: [{'a_code':, 'stock_name':, ...}, ...]
304 | a_code: A股代码
305 | stock_name: 股票名称
306 | a_price: A股价格
307 | a_increase_rt: A股涨跌幅(%)
308 | h_code: H股代码
309 | h_price: H股价格(港元)
310 | h_increase_rt: H股涨跌幅(%)
311 | last_time: 最后时间
312 | rmb_price: H股价格(人民币)
313 | hk_currency: 港元汇率
314 | ha_ratio: 比价(H/A)
315 | h_free_shares: H股自由流通市值(亿港元)
316 | a_free_shares: A股自由流通市值(亿元)
317 | """
318 | self._data = pd.DataFrame()
319 |
320 | self._data = self.__parsePage(cf.AH_RATIO_URL, cf.AH_RATIO_COLS)
321 | self._data[self._data=="-"] = np.NaN
322 | for col in ['a_price', 'a_increase_rt', 'h_price', 'h_increase_rt', 'rmb_price',
323 | 'hk_currency', 'ha_ratio', 'h_free_shares', 'a_free_shares']:
324 | self._data[col] = self._data[col].astype(float)
325 |
326 | return self._result()
327 |
328 |
329 | def dividendRate(self):
330 | """
331 | A股股息率
332 | return
333 | ------
334 | DataFrame or List: [{'stock_id':, 'stock_nm':, ...}, ...]
335 | stock_id: 股票代码
336 | stock_nm: 股票名称
337 | dividend_rate: 股息率(TTM)
338 | dividend_rate2: 静态股息率
339 | ipo_date: ipo日期
340 | price: 价格
341 | volume: 成交额(万元)
342 | increase_rt: 涨幅(%)
343 | pe: 市盈率(TTM)
344 | pb: 市净率
345 | total_value: 市值(亿元)
346 | eps_growth_ttm: 净利同比增长(%)
347 | roe: 最新年报ROE(%)
348 | revenue_average: 5年营收复合增长(%)
349 | profit_average: 5年利润复合增长(%)
350 | roe_average: 5年平均ROE(%)
351 | pb_temperature: PB温度(℃)
352 | pe_temperature: PE温度(℃)
353 | int_debt_rate: 有息负债率(%)
354 | cashflow_average: 5年现金流复合增长(%)
355 | dividend_rate_average: 5年分红率复合增长(%)
356 | dividend_rate5: 5年平均股息率(%)
357 | industry_nm: 所属行业
358 | active_flg: 活跃标志
359 | last_time: 最后时间
360 | """
361 | self._data = pd.DataFrame()
362 |
363 | self._data = self.__parsePage(cf.DIVIDEND_RATE_URL, cf.DIVIDEND_RATE_COLS)
364 | self._data[self._data=="-"] = np.NaN
365 | for col in ['dividend_rate', 'dividend_rate2', 'price', 'volume', 'increase_rt', 'pe', 'pb', 'total_value',
366 | 'eps_growth_ttm', 'roe', 'revenue_average', 'profit_average', 'roe_average', 'pb_temperature',
367 | 'pe_temperature', 'int_debt_rate', 'cashflow_average', 'dividend_rate_average', 'dividend_rate5']:
368 | self._data[col] = self._data[col].astype(float)
369 |
370 | return self._result()
371 |
372 |
373 | def stockLof(self):
374 | """
375 | 股票LOF基金及基相关数据
376 | return
377 | ------
378 | DataFrame or List: [{'fund_id':, 'fund_nm':, ...}, ...]
379 | fund_id: 基金代码
380 | fund_nm: 基金名称
381 | price: 现价
382 | increase_rt: 涨幅(%)
383 | volume: 成交(万元)
384 | amount: 场内份额(万份)
385 | fund_nav: 基金净值
386 | nav_dt: 净值日期
387 | estimate_value: 实时估值
388 | discount_rt: 溢价率(%)
389 | stock_ratio: 股票占比(%)
390 | stock_increase_rt: 重仓涨幅(%)
391 | apply_fee: 申购费(%)
392 | redeem_fee: 赎回费(%)
393 | apply_redeem_status: 申赎状态
394 | """
395 | self._data = pd.DataFrame()
396 |
397 | self._data = self.__parsePage(cf.STOCK_LOF_URL, cf.STOCK_LOF_COLS)
398 | for col in ['price', 'increase_rt', 'volume', 'amount', 'fund_nav',
399 | 'estimate_value', 'discount_rt', 'stock_ratio', 'stock_increase_rt', 'apply_fee', 'redeem_fee']:
400 | self._data[col] = self._data[col].astype(float)
401 |
402 | return self._result()
403 |
404 |
405 | def indexLof(self):
406 | """
407 | 指数LOF基金及基相关数据
408 | return
409 | ------
410 | DataFrame or List: [{'fund_id':, 'fund_nm':, ...}, ...]
411 | fund_id: 基金代码
412 | fund_nm: 基金名称
413 | price: 现价
414 | increase_rt: 涨幅(%)
415 | volume: 成交(万元)
416 | amount: 场内份额(万份)
417 | fund_nav: 基金净值
418 | nav_dt: 净值日期
419 | estimate_value: 实时估值
420 | discount_rt: 溢价率(%)
421 | index_id: 指数代码
422 | index_nm: 指数名称
423 | index_increase_rt: 指数涨幅(%)
424 | apply_fee: 申购费(%)
425 | redeem_fee: 赎回费(%)
426 | apply_redeem_status: 申赎状态
427 | """
428 | self._data = pd.DataFrame()
429 |
430 | self._data = self.__parsePage(cf.INDEX_LOF_URL, cf.INDEX_LOF_COLS)
431 | for col in ['price', 'increase_rt', 'volume', 'amount', 'fund_nav', 'estimate_value',
432 | 'discount_rt', 'index_increase_rt', 'apply_fee', 'redeem_fee']:
433 | self._data[col] = self._data[col].astype(float)
434 |
435 | return self._result()
436 |
437 |
438 | def __parsePage(self, url, column):
439 | page = 1
440 | while(True):
441 | try:
442 | request = self._session.get(url % page)
443 | text = request.text.replace('%', '')
444 | dataDict = json.loads(text)
445 | if dataDict['page'] < page:
446 | break
447 |
448 | dataList = []
449 | for row in dataDict['rows']:
450 | dataList.append(row['cell'])
451 |
452 | self._data = self._data.append(pd.DataFrame(dataList, columns = column), ignore_index=True)
453 |
454 | page += 1
455 | except Exception as e:
456 | print(str(e))
457 |
458 | return self._data
459 |
460 |
461 |
--------------------------------------------------------------------------------
/GuGu/macro.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | """
3 | 宏观经济数据类
4 | Created on 2019/01/09
5 | @author: TabQ
6 | @group : GuGu
7 | @contact: 16621596@qq.com
8 | """
9 | import pandas as pd
10 | import numpy as np
11 | import re
12 | import json
13 | import time
14 | from utility import Utility
15 | from base import Base, cf
16 |
17 |
18 | class Macro(Base):
19 | def gdpYear(self, retry=3, pause=0.001):
20 | """
21 | 获取年度国内生产总值数据
22 | Parameters
23 | --------
24 | retry : int, 默认 3
25 | 如遇网络等问题重复执行的次数
26 | pause : int, 默认 0.001
27 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
28 |
29 | Return
30 | --------
31 | DataFrame or List: [{'year':, 'gdp':, ...}, ...]
32 | year :统计年度
33 | gdp :国内生产总值(亿元)
34 | pc_gdp :人均国内生产总值(元)
35 | gnp :国民生产总值(亿元)
36 | pi :第一产业(亿元)
37 | si :第二产业(亿元)
38 | industry :工业(亿元)
39 | cons_industry :建筑业(亿元)
40 | ti :第三产业(亿元)
41 | trans_industry :交通运输仓储邮电通信业(亿元)
42 | lbdy :批发零售贸易及餐饮业(亿元)
43 | """
44 | self._data = pd.DataFrame()
45 |
46 | # http://money.finance.sina.com.cn/mac/api/jsonp.php/SINAREMOTECALLCALLBACK4224641560861/MacPage_Service.get_pagedata?cate=nation&event=0&from=0&num=70&condition=&_=4224641560861
47 | datastr = self.__parsePage('nation', 0, 70, retry, pause)
48 | datastr = datastr.replace('"', '').replace('null', '0')
49 | js = json.loads(datastr)
50 | self._data = pd.DataFrame(js, columns=cf.GDP_YEAR_COLS)
51 | self._data[self._data==0] = np.NaN
52 |
53 | return self._result()
54 |
55 | def gdpQuarter(self, retry=3, pause=0.001):
56 | """
57 | 获取季度国内生产总值数据
58 | Parameters
59 | --------
60 | retry : int, 默认 3
61 | 如遇网络等问题重复执行的次数
62 | pause : int, 默认 0.001
63 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
64 |
65 | Return
66 | --------
67 | DataFrame or List: [{'quarter':, 'gdp':, ...}, ...]
68 | quarter :季度
69 | gdp :国内生产总值(亿元)
70 | gdp_yoy :国内生产总值同比增长(%)
71 | pi :第一产业增加值(亿元)
72 | pi_yoy:第一产业增加值同比增长(%)
73 | si :第二产业增加值(亿元)
74 | si_yoy :第二产业增加值同比增长(%)
75 | ti :第三产业增加值(亿元)
76 | ti_yoy :第三产业增加值同比增长(%)
77 | """
78 | self._data = pd.DataFrame()
79 |
80 | # http://money.finance.sina.com.cn/mac/api/jsonp.php/SINAREMOTECALLCALLBACK3935140379887/MacPage_Service.get_pagedata?cate=nation&event=1&from=0&num=250&condition=&_=3935140379887
81 | datastr = self.__parsePage('nation', 1, 250, retry, pause)
82 | datastr = datastr.replace('"', '').replace('null', '0')
83 | js = json.loads(datastr)
84 | self._data = pd.DataFrame(js, columns=cf.GDP_QUARTER_COLS)
85 | self._data['quarter'] = self._data['quarter'].astype(object)
86 | self._data[self._data==0] = np.NaN
87 |
88 | return self._result()
89 |
90 | def demandsToGdp(self, retry=3, pause=0.001):
91 | """
92 | 获取三大需求对GDP贡献数据
93 | Parameters
94 | --------
95 | retry : int, 默认 3
96 | 如遇网络等问题重复执行的次数
97 | pause : int, 默认 0.001
98 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
99 |
100 | Return
101 | --------
102 | DataFrame or List: [{'year':, 'cons_to':, ...}, ...]
103 | year :统计年度
104 | cons_to :最终消费支出贡献率(%)
105 | cons_rate :最终消费支出拉动(百分点)
106 | asset_to :资本形成总额贡献率(%)
107 | asset_rate:资本形成总额拉动(百分点)
108 | goods_to :货物和服务净出口贡献率(%)
109 | goods_rate :货物和服务净出口拉动(百分点)
110 | """
111 | self._data = pd.DataFrame()
112 |
113 | # http://money.finance.sina.com.cn/mac/api/jsonp.php/SINAREMOTECALLCALLBACK3153587567694/MacPage_Service.get_pagedata?cate=nation&event=4&from=0&num=80&condition=&_=3153587567694
114 | datastr = self.__parsePage('nation', 4, 80, retry, pause)
115 | datastr = datastr.replace('"','').replace('null','0')
116 | js = json.loads(datastr)
117 | self._data = pd.DataFrame(js,columns=cf.GDP_FOR_COLS)
118 | self._data[self._data==0] = np.NaN
119 |
120 | return self._result()
121 |
122 |
123 | def idsPullToGdp(self, retry=3, pause=0.001):
124 | """
125 | 获取三大产业对GDP拉动数据
126 | Parameters
127 | --------
128 | retry : int, 默认 3
129 | 如遇网络等问题重复执行的次数
130 | pause : int, 默认 0.001
131 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
132 |
133 | Return
134 | --------
135 | DataFrame or List: [{'year':, 'gdp_yoy':, ...}, ...]
136 | year :统计年度
137 | gdp_yoy :国内生产总值同比增长(%)
138 | pi :第一产业拉动率(%)
139 | si :第二产业拉动率(%)
140 | industry:其中工业拉动(%)
141 | ti :第三产业拉动率(%)
142 | """
143 | self._data = pd.DataFrame()
144 |
145 | # http://money.finance.sina.com.cn/mac/api/jsonp.php/SINAREMOTECALLCALLBACK1083239038283/MacPage_Service.get_pagedata?cate=nation&event=5&from=0&num=60&condition=&_=1083239038283
146 | datastr = self.__parsePage('nation', 5, 60, retry, pause)
147 | datastr = datastr.replace('"', '').replace('null', '0')
148 | js = json.loads(datastr)
149 | self._data = pd.DataFrame(js, columns=cf.GDP_PULL_COLS)
150 | self._data[self._data==0] = np.NaN
151 |
152 | return self._result()
153 |
154 |
155 | def idsCtbToGdp(self, retry=3, pause=0.001):
156 | """
157 | 获取三大产业贡献率数据
158 | Parameters
159 | --------
160 | retry : int, 默认 3
161 | 如遇网络等问题重复执行的次数
162 | pause : int, 默认 0.001
163 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
164 |
165 | Return
166 | --------
167 | DataFrame or List: [{'year':, 'gdp_yoy':, ...}, ...]
168 | year :统计年度
169 | gdp_yoy :国内生产总值
170 | pi :第一产业献率(%)
171 | si :第二产业献率(%)
172 | industry:其中工业献率(%)
173 | ti :第三产业献率(%)
174 | """
175 | self._data = pd.DataFrame()
176 |
177 | # http://money.finance.sina.com.cn/mac/api/jsonp.php/SINAREMOTECALLCALLBACK4658347026358/MacPage_Service.get_pagedata?cate=nation&event=6&from=0&num=60&condition=&_=4658347026358
178 | datastr = self.__parsePage('nation', 6, 60, retry, pause)
179 | datastr = datastr.replace('"', '').replace('null', '0')
180 | js = json.loads(datastr)
181 | self._data = pd.DataFrame(js, columns=cf.GDP_CONTRIB_COLS)
182 | self._data[self._data==0] = np.NaN
183 |
184 | return self._result()
185 |
186 |
187 | def cpi(self, retry=3, pause=0.001):
188 | """
189 | 获取居民消费价格指数数据
190 | Parameters
191 | --------
192 | retry : int, 默认 3
193 | 如遇网络等问题重复执行的次数
194 | pause : int, 默认 0.001
195 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
196 |
197 | Return
198 | --------
199 | DataFrame or List: [{'month':, 'cpi':,}, ...]
200 | month :统计月份
201 | cpi :价格指数
202 | """
203 | self._data = pd.DataFrame()
204 |
205 | datastr = self.__parsePage('price', 0, 600, retry, pause)
206 | js = json.loads(datastr)
207 | self._data = pd.DataFrame(js, columns=cf.CPI_COLS)
208 | self._data['cpi'] = self._data['cpi'].astype(float)
209 |
210 | return self._result()
211 |
212 |
213 | def ppi(self, retry=3, pause=0.001):
214 | """
215 | 获取工业品出厂价格指数数据
216 | Parameters
217 | --------
218 | retry : int, 默认 3
219 | 如遇网络等问题重复执行的次数
220 | pause : int, 默认 0.001
221 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
222 |
223 | Return
224 | --------
225 | DataFrame or List: [{'month':, 'ppiip':, ...}, ...]
226 | month :统计月份
227 | ppiip :工业品出厂价格指数
228 | ppi :生产资料价格指数
229 | qm:采掘工业价格指数
230 | rmi:原材料工业价格指数
231 | pi:加工工业价格指数
232 | cg:生活资料价格指数
233 | food:食品类价格指数
234 | clothing:衣着类价格指数
235 | roeu:一般日用品价格指数
236 | dcg:耐用消费品价格指数
237 | """
238 | self._data = pd.DataFrame()
239 |
240 | # http://money.finance.sina.com.cn/mac/api/jsonp.php/SINAREMOTECALLCALLBACK6734345383111/MacPage_Service.get_pagedata?cate=price&event=3&from=0&num=600&condition=&_=6734345383111
241 | datastr = self.__parsePage('price', 3, 600, retry, pause)
242 | js = json.loads(datastr)
243 | self._data = pd.DataFrame(js, columns=cf.PPI_COLS)
244 | for i in self._data.columns:
245 | self._data[i] = self._data[i].apply(lambda x:np.where(x is None, np.NaN, x))
246 | if i != 'month':
247 | self._data[i] = self._data[i].astype(float)
248 |
249 | return self._result()
250 |
251 |
252 | def depositRate(self, retry=3, pause=0.001):
253 | """
254 | 获取存款利率数据
255 | Parameters
256 | --------
257 | retry : int, 默认 3
258 | 如遇网络等问题重复执行的次数
259 | pause : int, 默认 0.001
260 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
261 |
262 | Return
263 | --------
264 | DataFrame or List: [{'date':, 'deposit_type':, ...}, ...]
265 | date :变动日期
266 | deposit_type :存款种类
267 | rate:利率(%)
268 | """
269 | self._data = pd.DataFrame()
270 |
271 | # http://money.finance.sina.com.cn/mac/api/jsonp.php/SINAREMOTECALLCALLBACK1250640915421/MacPage_Service.get_pagedata?cate=fininfo&event=2&from=0&num=600&condition=&_=1250640915421
272 | datastr = self.__parsePage('fininfo', 2, 600, retry, pause)
273 | js = json.loads(datastr)
274 | self._data = pd.DataFrame(js, columns=cf.DEPOSIT_COLS)
275 | for i in self._data.columns:
276 | self._data[i] = self._data[i].apply(lambda x:np.where(x is None, '--', x))
277 |
278 | return self._result()
279 |
280 |
281 | def loanRate(self, retry=3, pause=0.001):
282 | """
283 | 获取贷款利率数据
284 | Parameters
285 | --------
286 | retry : int, 默认 3
287 | 如遇网络等问题重复执行的次数
288 | pause : int, 默认 0.001
289 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
290 |
291 | Return
292 | --------
293 | DataFrame or List: [{'date':, 'loan_type':, ...}, ...]
294 | date :执行日期
295 | loan_type :存款种类
296 | rate:利率(%)
297 | """
298 | self._data = pd.DataFrame()
299 |
300 | # http://money.finance.sina.com.cn/mac/api/jsonp.php/SINAREMOTECALLCALLBACK7542659823280/MacPage_Service.get_pagedata?cate=fininfo&event=3&from=0&num=800&condition=&_=7542659823280
301 | datastr = self.__parsePage('fininfo', 3, 800, retry, pause)
302 | js = json.loads(datastr)
303 | self._data = pd.DataFrame(js, columns=cf.LOAN_COLS)
304 | for i in self._data.columns:
305 | self._data[i] = self._data[i].apply(lambda x:np.where(x is None, '--', x))
306 |
307 | return self._result()
308 |
309 |
310 | def rrr(self, retry=3, pause=0.001):
311 | """
312 | 获取存款准备金率数据
313 | Parameters
314 | --------
315 | retry : int, 默认 3
316 | 如遇网络等问题重复执行的次数
317 | pause : int, 默认 0.001
318 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
319 |
320 | Return
321 | --------
322 | DataFrame or List: [{'date':, 'before':, ...}, ...]
323 | date :变动日期
324 | before :调整前存款准备金率(%)
325 | now:调整后存款准备金率(%)
326 | changed:调整幅度(%)
327 | """
328 | self._data = pd.DataFrame()
329 |
330 | # http://money.finance.sina.com.cn/mac/api/jsonp.php/SINAREMOTECALLCALLBACK8028217046046/MacPage_Service.get_pagedata?cate=fininfo&event=4&from=0&num=100&condition=&_=8028217046046
331 | datastr = self.__parsePage('fininfo', 4, 100, retry, pause)
332 | datastr = datastr if self._PY3 else datastr.decode('gbk')
333 | js = json.loads(datastr)
334 | self._data = pd.DataFrame(js, columns=cf.RRR_COLS)
335 | for i in self._data.columns:
336 | self._data[i] = self._data[i].apply(lambda x:np.where(x is None, '--', x))
337 |
338 | return self._result()
339 |
340 |
341 | def montySupply(self, retry=3, pause=0.001):
342 | """
343 | 获取货币供应量数据
344 | Parameters
345 | --------
346 | retry : int, 默认 3
347 | 如遇网络等问题重复执行的次数
348 | pause : int, 默认 0.001
349 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
350 |
351 | Return
352 | --------
353 | DataFrame or List: [{'month':, 'm2':, ...}, ...]
354 | month :统计时间
355 | m2 :货币和准货币(广义货币M2)(亿元)
356 | m2_yoy:货币和准货币(广义货币M2)同比增长(%)
357 | m1:货币(狭义货币M1)(亿元)
358 | m1_yoy:货币(狭义货币M1)同比增长(%)
359 | m0:流通中现金(M0)(亿元)
360 | m0_yoy:流通中现金(M0)同比增长(%)
361 | cd:活期存款(亿元)
362 | cd_yoy:活期存款同比增长(%)
363 | qm:准货币(亿元)
364 | qm_yoy:准货币同比增长(%)
365 | ftd:定期存款(亿元)
366 | ftd_yoy:定期存款同比增长(%)
367 | sd:储蓄存款(亿元)
368 | sd_yoy:储蓄存款同比增长(%)
369 | rests:其他存款(亿元)
370 | rests_yoy:其他存款同比增长(%)
371 | """
372 | self._data = pd.DataFrame()
373 |
374 | # http://money.finance.sina.com.cn/mac/api/jsonp.php/SINAREMOTECALLCALLBACK9019314616219/MacPage_Service.get_pagedata?cate=fininfo&event=1&from=0&num=600&condition=&_=9019314616219
375 | datastr = self.__parsePage('fininfo', 1, 600, retry, pause)
376 | datastr = datastr if self._PY3 else datastr.decode('gbk')
377 | js = json.loads(datastr)
378 | self._data = pd.DataFrame(js, columns=cf.MONEY_SUPPLY_COLS)
379 | for i in self._data.columns:
380 | self._data[i] = self._data[i].apply(lambda x:np.where(x is None, '--', x))
381 |
382 | return self._result()
383 |
384 |
385 | def moneySupplyBal(self, retry=3, pause=0.001):
386 | """
387 | 获取货币供应量(年底余额)数据
388 | Parameters
389 | --------
390 | retry : int, 默认 3
391 | 如遇网络等问题重复执行的次数
392 | pause : int, 默认 0.001
393 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
394 |
395 | Return
396 | --------
397 | DataFrame or List: [{'year':, 'm2':, ...}, ...]
398 | year :统计年度
399 | m2 :货币和准货币(亿元)
400 | m1:货币(亿元)
401 | m0:流通中现金(亿元)
402 | cd:活期存款(亿元)
403 | qm:准货币(亿元)
404 | ftd:定期存款(亿元)
405 | sd:储蓄存款(亿元)
406 | rests:其他存款(亿元)
407 | """
408 | self._data = pd.DataFrame()
409 |
410 | # http://money.finance.sina.com.cn/mac/api/jsonp.php/SINAREMOTECALLCALLBACK3430820865181/MacPage_Service.get_pagedata?cate=fininfo&event=0&from=0&num=200&condition=&_=3430820865181
411 | datastr = self.__parsePage('fininfo', 0, 200, retry, pause)
412 | datastr = datastr if self._PY3 else datastr.decode('gbk')
413 | js = json.loads(datastr)
414 | self._data = pd.DataFrame(js, columns=cf.MONEY_SUPPLY_BLA_COLS)
415 | for i in self._data.columns:
416 | self._data[i] = self._data[i].apply(lambda x:np.where(x is None, '--', x))
417 |
418 | return self._result()
419 |
420 |
421 | def __parsePage(self, cate='', event=0, num=0, retry=3, pause=0.001):
422 | for _ in range(retry):
423 | time.sleep(pause)
424 |
425 | try:
426 | rdInt = Utility.random()
427 | request = self._session.get( cf.MACRO_URL % (rdInt, cate, event, num, rdInt), timeout=10 )
428 | if self._PY3:
429 | request.encoding = 'gbk'
430 |
431 | regSym = re.compile(r'\,count:(.*?)\}')
432 | datastr = regSym.findall(request.text)
433 | datastr = datastr[0]
434 | datastr = datastr.split('data:')[1]
435 | except Exception as e:
436 | print(e)
437 | else:
438 | return datastr
439 |
440 | raise IOError(cf.NETWORK_URL_ERROR_MSG)
441 |
442 |
443 | def shibor(self, year=None):
444 | """
445 | 获取上海银行间同业拆放利率
446 | Parameters
447 | ------
448 | year:年份(int)
449 |
450 | Return
451 | ------
452 | DataFrame or List: [{'date':, 'ON':, ...}, ...]
453 | date:日期
454 | ON:隔夜拆放利率
455 | 1W:1周拆放利率
456 | 2W:2周拆放利率
457 | 1M:1个月拆放利率
458 | 3M:3个月拆放利率
459 | 6M:6个月拆放利率
460 | 9M:9个月拆放利率
461 | 1Y:1年拆放利率
462 | """
463 | self._data = pd.DataFrame()
464 |
465 | lab = cf.SHIBOR_TYPE['Shibor']
466 | # http://www.shibor.org/shibor/web/html/downLoad.html?nameNew=Historical_Shibor_Data_2018.xls&downLoadPath=data&nameOld=Shibor数据2018.xls&shiborSrc=http://www.shibor.org/shibor/
467 | self._data = self.__parseExcel(year, 'Shibor', lab, cf.SHIBOR_COLS)
468 |
469 | return self._result()
470 |
471 |
472 | def shiborQuote(self, year=None):
473 | """
474 | 获取Shibor银行报价数据
475 | Parameters
476 | ------
477 | year:年份(int)
478 |
479 | Return
480 | ------
481 | DataFrame or List: [{'date':, 'bank':, ...}, ...]
482 | date:日期
483 | bank:报价银行名称
484 | ON:隔夜拆放利率
485 | 1W:1周拆放利率
486 | 2W:2周拆放利率
487 | 1M:1个月拆放利率
488 | 3M:3个月拆放利率
489 | 6M:6个月拆放利率
490 | 9M:9个月拆放利率
491 | 1Y:1年拆放利率
492 | """
493 | self._data = pd.DataFrame()
494 |
495 | lab = cf.SHIBOR_TYPE['Quote']
496 | # http://www.shibor.org/shibor/web/html/downLoad.html?nameNew=Historical_Quote_Data_2018.xls&downLoadPath=data&nameOld=报价数据2018.xls&shiborSrc=http://www.shibor.org/shibor/
497 | self._data = self.__parseExcel(year, 'Quote', lab, cf.QUOTE_COLS)
498 |
499 | return self._result()
500 |
501 |
502 | def shiborMa(self, year=None):
503 | """
504 | 获取Shibor均值数据
505 | Parameters
506 | ------
507 | year:年份(int)
508 |
509 | Return
510 | ------
511 | DataFrame or List: [{'date':, 'ON_5':, ...}, ...]
512 | date:日期
513 | 其它分别为各周期5、10、20均价
514 | """
515 | self._data = pd.DataFrame()
516 |
517 | lab = cf.SHIBOR_TYPE['Tendency']
518 | self._data = self.__parseExcel(year, 'Shibor_Tendency', lab, cf.SHIBOR_MA_COLS)
519 |
520 | return self._result()
521 |
522 |
523 | def lpr(self, year=None):
524 | """
525 | 获取贷款基础利率
526 | Parameters
527 | ------
528 | year:年份(int)
529 |
530 | Return
531 | ------
532 | DataFrame or List: [{'date':, '1Y':, ...}, ...]
533 | date:日期
534 | 1Y:1年贷款基础利率
535 | """
536 | self._data = pd.DataFrame()
537 |
538 | lab = cf.SHIBOR_TYPE['LPR']
539 | self._data = self.__parseExcel(year, 'LPR', lab, cf.LPR_COLS)
540 |
541 | return self._result()
542 |
543 |
544 | def lprMa(self, year=None):
545 | """
546 | 获取贷款基础利率均值数据
547 | Parameters
548 | ------
549 | year:年份(int)
550 |
551 | Return
552 | ------
553 | DataFrame or List: [{'date':, '1Y_5':, ...}, ...]
554 | date:日期
555 | 1Y_5:5日均值
556 | 1Y_10:10日均值
557 | 1Y_20:20日均值
558 | """
559 | self._data = pd.DataFrame()
560 |
561 | lab = cf.SHIBOR_TYPE['LPR_Tendency']
562 | self._data = self.__parseExcel(year, 'LPR_Tendency', lab, cf.LPR_MA_COLS)
563 |
564 | return self._result()
565 |
566 |
567 | def __parseExcel(self, year, datatype, lab, column):
568 | year = Utility.getYear() if year is None else year
569 | lab = lab.encode('utf-8') if self._PY3 else lab
570 |
571 | try:
572 | df = pd.read_excel( cf.SHIBOR_DATA_URL % (datatype, year, lab, year), skiprows=[0] )
573 | df.columns = column
574 | df['date'] = df['date'].map(lambda x: x.date())
575 | df['date'] = df['date'].astype('datetime64[ns]')
576 | except Exception as e:
577 | print(e)
578 | else:
579 | return df
580 |
581 |
582 |
--------------------------------------------------------------------------------
/GuGu/marketdata.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | """
3 | 市场类
4 | Created on 2018/12/26
5 | @author: TabQ
6 | @group : GuGu
7 | @contact: 16621596@qq.com
8 | """
9 |
10 | import pandas as pd
11 | from pandas.compat import StringIO
12 | import re
13 | import json
14 | import numpy as np
15 | from base import Base, cf
16 |
17 |
18 | class MarketData(Base):
19 | def index(self):
20 | """
21 | 获取大盘指数行情
22 | return
23 | -------
24 | DataFrame or list: [{'code':, 'name':, ...}, ...]
25 | code:指数代码
26 | name:指数名称
27 | change:涨跌幅
28 | open:开盘价
29 | preclose:昨日收盘价
30 | close:收盘价
31 | high:最高价
32 | low:最低价
33 | volume:成交量(手)
34 | amount:成交金额(亿元)
35 | """
36 | self._data = pd.DataFrame()
37 |
38 | # http://hq.sinajs.cn/rn=xppzh&list=sh000001,sh000002,sh000003,sh000008,sh000009,sh000010,sh000011,sh000012,sh000016,sh000017,sh000300,sh000905,sz399001,sz399002,sz399003,sz399004,sz399005,sz399006,sz399008,sz399100,sz399101,sz399106,sz399107,sz399108,sz399333,sz399606
39 | request = self._session.get( cf.INDEX_URL, timeout=10 )
40 | request.encoding = 'gbk'
41 | text = request.text.replace('var hq_str_', '')
42 | text = text.replace('";', '').replace('"', '').replace('=', ',')
43 | text = '%s%s'%(cf.INDEX_HEADER, text)
44 |
45 | self._data = pd.read_csv(StringIO(text), sep=',', thousands=',')
46 | self._data['change'] = (self._data['close'] / self._data['preclose'] - 1 ) * 100
47 | self._data['amount'] = self._data['amount'] / 100000000
48 | self._data['change'] = self._data['change'].map(cf.FORMAT)
49 | self._data['amount'] = self._data['amount'].map(cf.FORMAT4)
50 | self._data = self._data[cf.INDEX_COLS]
51 | self._data['code'] = self._data['code'].map(lambda x:str(x).zfill(6))
52 | self._data['change'] = self._data['change'].astype(float)
53 | self._data['amount'] = self._data['amount'].astype(float)
54 |
55 | return self._result()
56 |
57 |
58 | def latest(self):
59 | """
60 | 一次性获取最近一个日交易日所有股票的交易数据
61 | return
62 | -------
63 | DataFrame or list: [{'code':, 'name':, ...}, ...]
64 | 属性:代码,名称,涨跌幅,现价,开盘价,最高价,最低价,最日收盘价,成交量,换手率,成交额,市盈率,市净率,总市值,流通市值
65 | """
66 | self._data = pd.DataFrame()
67 |
68 | self._writeHead()
69 |
70 | self._data = self.__handleLatest(1)
71 | if self._data is not None:
72 | for i in range(2, cf.PAGE_NUM[0]):
73 | newData = self.__handleLatest(i)
74 | self._data = self._data.append(newData, ignore_index=True)
75 |
76 | return self._result()
77 |
78 |
79 | def __handleLatest(self, pageNum=1):
80 | """
81 | 处理当日行情分页数据,格式为json
82 | Parameters
83 | ------
84 | pageNum:页码
85 | return
86 | -------
87 | DataFrame 当日所有股票交易数据(DataFrame)
88 | """
89 | self._writeConsole()
90 | # http://vip.stock.finance.sina.com.cn/quotes_service/api/json_v2.php/Market_Center.getHQNodeData?num=80&sort=code&asc=0&node=hs_a&symbol=&_s_r_a=page&page=1
91 | request = self._session.get( cf.LATEST_URL % pageNum, timeout=10 )
92 | if self._PY3:
93 | request.encoding = 'gbk'
94 | text = request.text
95 | if text == 'null':
96 | return None
97 |
98 | reg = re.compile(r'\,(.*?)\:')
99 | text = reg.sub(r',"\1":', text)
100 | text = text.replace('"{symbol', '{"symbol')
101 | text = text.replace('{symbol', '{"symbol"')
102 | jstr = json.dumps(text)
103 | js = json.loads(jstr)
104 | df = pd.DataFrame(pd.read_json(js, dtype={'code':object}), columns=cf.DAY_TRADING_COLUMNS)
105 | df = df.drop('symbol', axis=1)
106 |
107 | return df
108 |
109 |
110 | def indexETF(self):
111 | """
112 | 获取指数ETF及其相关数据
113 | return
114 | ------
115 | DataFrame or List: [{'fund_id':, 'fund_nm':, ...}, ...]
116 | fund_id: 基金代码
117 | fund_nm: 基金名称
118 | index_id: 跟踪指数代码
119 | creation_unit: 最小申赎单位(万份)
120 | amount: 份额(万份)
121 | unit_total: 规模(亿元)
122 | unit_incr: 规模变化(亿元)
123 | price: 现价
124 | volume: 成交额(万元)
125 | increase_rt: 涨幅(%)
126 | estimate_value: 估值
127 | discount_rt: 溢价率(%)
128 | fund_nav: 净值
129 | nav_dt: 净值日期
130 | index_nm: 指数名称
131 | index_increase_rt: 指数涨幅(%)
132 | pe: 市盈率
133 | pb: 市净率
134 | """
135 | self._data = pd.DataFrame()
136 |
137 | page = 1
138 | while(True):
139 | try:
140 | request = self._session.get( cf.INDEX_ETF_URL % page )
141 | text = request.text.replace('%', '')
142 | dataDict = json.loads(text)
143 | if dataDict['page'] < page:
144 | break
145 |
146 | dataList = []
147 | for row in dataDict['rows']:
148 | dataList.append(row['cell'])
149 | self._data = self._data.append(pd.DataFrame(dataList, columns = cf.INDEX_ETF_COLS), ignore_index=True)
150 |
151 | page += 1
152 | except Exception as e:
153 | print(str(e))
154 |
155 | self._data[self._data=="-"] = np.NaN
156 | for col in ['creation_unit', 'amount', 'unit_total', 'unit_incr', 'price', 'volume', 'increase_rt',
157 | 'estimate_value', 'discount_rt', 'fund_nav', 'index_increase_rt', 'pe', 'pb']:
158 | self._data[col] = self._data[col].astype(float)
159 |
160 | self._data['index_id'] = self._data['index_id'].map(lambda x : x if x != "0" else None)
161 |
162 | return self._result()
163 |
164 |
165 |
--------------------------------------------------------------------------------
/GuGu/reference.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | """
3 | 投资参考类
4 | Created on 2019/01/03
5 | @author: TabQ
6 | @group : GuGu
7 | @contact: 16621596@qq.com
8 | """
9 |
10 | from __future__ import division
11 |
12 | import math
13 | import time
14 | import pandas as pd
15 | from pandas.compat import StringIO
16 | import lxml.html
17 | from lxml import etree
18 | import re
19 | import json
20 | from utility import Utility
21 | from base import Base, cf
22 |
23 | class Reference(Base):
24 | def distriPlan(self, year=2015, top=25, retry=3, pause=0.001):
25 | """
26 | 获取分配预案数据
27 | Parameters
28 | --------
29 | year:年份
30 | top:取最新n条数据,默认取最近公布的25条
31 | retry : int, 默认 3
32 | 如遇网络等问题重复执行的次数
33 | pause : int, 默认 0.001
34 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
35 |
36 | returns
37 | -------
38 | DataFrame or List: [{'code', 'name', ...}, ...]
39 | code:股票代码
40 | name:股票名称
41 | year:分配年份
42 | report_date:公布日期
43 | divi:分红金额(每10股)
44 | shares:转增和送股数(每10股)
45 | """
46 | self._data = pd.DataFrame()
47 |
48 | if top == 'all':
49 | self._writeHead()
50 |
51 | self._data, pages = self.__handleDistriPlan(year, 0, retry, pause)
52 | for i in range(1, int(pages)):
53 | self._data = self._data.append(self.__handleDistriPlan(year, i, retry, pause), ignore_index=True)
54 |
55 | return self._result()
56 | elif top <= 25:
57 | self._data, pages = self.__handleDistriPlan(year, 0, retry, pause)
58 | self._data = self._data.head(top)
59 |
60 | return self._result()
61 | else:
62 | if isinstance(top, int):
63 | self._writeHead()
64 |
65 | allPages = int(math.ceil(top/25))
66 | self._data, pages = self.__handleDistriPlan(year, 0, retry, pause)
67 | pages = min(allPages, int(pages))
68 | for i in range(1, pages):
69 | self._data = self._data.append(self.__handleDistriPlan(year, i, retry, pause), ignore_index=True)
70 |
71 | self._data = self._data.head(top)
72 |
73 | return self._result()
74 | else:
75 | print(cf.TOP_PARAS_MSG)
76 |
77 |
78 | def __handleDistriPlan(self, year, pageNo, retry, pause):
79 | for _ in range(retry):
80 | time.sleep(pause)
81 |
82 | try:
83 | if pageNo > 0:
84 | self._writeConsole()
85 |
86 | # http://quotes.money.163.com/data/caibao/fpyg.html?reportdate=2018&sort=declaredate&order=desc&page=0
87 | html = lxml.html.parse(cf.DP_163_URL % (year, pageNo))
88 | res = html.xpath('//table[@class=\"fn_cm_table\"]/tr')
89 | if self._PY3:
90 | sarr = [etree.tostring(node).decode('utf-8') for node in res]
91 | else:
92 | sarr = [etree.tostring(node) for node in res]
93 | sarr = ''.join(sarr)
94 | sarr = '' % sarr
95 | df = pd.read_html(sarr)[0]
96 | df = df.drop(0, axis=1)
97 | df.columns = cf.DP_163_COLS
98 | df['divi'] = df['plan'].map(self.__bonus)
99 | df['shares'] = df['plan'].map(self.__gift)
100 | df = df.drop('plan', axis=1)
101 | df['code'] = df['code'].astype(object)
102 | df['code'] = df['code'].map(lambda x : str(x).zfill(6))
103 | pages = []
104 | if pageNo == 0:
105 | page = html.xpath('//div[@class=\"mod_pages\"]/a')
106 | if len(page)>1:
107 | asr = page[len(page)-2]
108 | pages = asr.xpath('text()')
109 | except Exception as e:
110 | print(e)
111 | else:
112 | if pageNo == 0:
113 | return df, pages[0] if len(pages)>0 else 0
114 | else:
115 | return df
116 |
117 | raise IOError(cf.NETWORK_URL_ERROR_MSG)
118 |
119 |
120 | def __bonus(self, x):
121 | if self._PY3:
122 | reg = re.compile(r'分红(.*?)元', re.UNICODE)
123 | res = reg.findall(x)
124 | return 0 if len(res)<1 else float(res[0])
125 | else:
126 | if isinstance(x, unicode):
127 | s1 = unicode('分红','utf-8')
128 | s2 = unicode('元','utf-8')
129 | reg = re.compile(r'%s(.*?)%s'%(s1, s2), re.UNICODE)
130 | res = reg.findall(x)
131 | return 0 if len(res)<1 else float(res[0])
132 | else:
133 | return 0
134 |
135 |
136 | def __gift(self, x):
137 | if self._PY3:
138 | reg1 = re.compile(r'转增(.*?)股', re.UNICODE)
139 | reg2 = re.compile(r'送股(.*?)股', re.UNICODE)
140 | res1 = reg1.findall(x)
141 | res2 = reg2.findall(x)
142 | res1 = 0 if len(res1)<1 else float(res1[0])
143 | res2 = 0 if len(res2)<1 else float(res2[0])
144 |
145 | return res1 + res2
146 | else:
147 | if isinstance(x, unicode):
148 | s1 = unicode('转增','utf-8')
149 | s2 = unicode('送股','utf-8')
150 | s3 = unicode('股','utf-8')
151 | reg1 = re.compile(r'%s(.*?)%s'%(s1, s3), re.UNICODE)
152 | reg2 = re.compile(r'%s(.*?)%s'%(s2, s3), re.UNICODE)
153 | res1 = reg1.findall(x)
154 | res2 = reg2.findall(x)
155 | res1 = 0 if len(res1)<1 else float(res1[0])
156 | res2 = 0 if len(res2)<1 else float(res2[0])
157 |
158 | return res1 + res2
159 | else:
160 | return 0
161 |
162 |
163 | def forecast(self, year, quarter, retry=3, pause=0.001):
164 | """
165 | 获取业绩预告数据
166 | Parameters
167 | --------
168 | year:int 年度 e.g:2014
169 | quarter:int 季度 :1、2、3、4,只能输入这4个季度
170 | 说明:由于是从网站获取的数据,需要一页页抓取,速度取决于您当前网络速度
171 | retry : int, 默认 3
172 | 如遇网络等问题重复执行的次数
173 | pause : int, 默认 0.001
174 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
175 | Return
176 | --------
177 | DataFrame or List: [{'code':, 'name':, ...}, ...]
178 | code,代码
179 | name,名称
180 | type,业绩变动类型【预增、预亏等】
181 | report_date,发布日期
182 | pre_eps,上年同期每股收益
183 | range,业绩变动范围
184 | """
185 | self._data = pd.DataFrame()
186 |
187 | if Utility.checkQuarter(year, quarter) is True:
188 | self._writeHead()
189 | self._data = self.__handleForecast(year, quarter, 1, pd.DataFrame(), retry, pause)
190 | self._data = pd.DataFrame(self._data, columns=cf.FORECAST_COLS)
191 | self._data['code'] = self._data['code'].map(lambda x: str(x).zfill(6))
192 |
193 | return self._result()
194 |
195 |
196 | def __handleForecast(self, year, quarter, pageNo, dataArr, retry, pause):
197 | self._writeConsole()
198 |
199 | for _ in range(retry):
200 | time.sleep(pause)
201 |
202 | try:
203 | # http://vip.stock.finance.sina.com.cn/q/go.php/vFinanceAnalyze/kind/performance/index.phtml?s_i=&s_a=&s_c=&s_type=&reportdate=2018&quarter=3&p=1&num=60
204 | request = self._session.get( cf.FORECAST_URL%( year, quarter, pageNo, cf.PAGE_NUM[1]), timeout=10 )
205 | request.encoding = 'gbk'
206 | text = request.text.replace('--', '')
207 | html = lxml.html.parse(StringIO(text))
208 | res = html.xpath("//table[@class=\"list_table\"]/tr")
209 | if self._PY3:
210 | sarr = [etree.tostring(node).decode('utf-8') for node in res]
211 | else:
212 | sarr = [etree.tostring(node) for node in res]
213 | sarr = ''.join(sarr)
214 | sarr = ''%sarr
215 | df = pd.read_html(sarr)[0]
216 | df = df.drop([4, 5, 8], axis=1)
217 | df.columns = cf.FORECAST_COLS
218 | dataArr = dataArr.append(df, ignore_index=True)
219 | nextPage = html.xpath('//div[@class=\"pages\"]/a[last()]/@onclick')
220 | if len(nextPage)>0:
221 | pageNo = re.findall(r'\d+',nextPage[0])[0]
222 | return self.__handleForecast(year, quarter, pageNo, dataArr, retry, pause)
223 | else:
224 | return dataArr
225 | except Exception as e:
226 | print(e)
227 |
228 | raise IOError(cf.NETWORK_URL_ERROR_MSG)
229 |
230 |
231 | def restrictedLift(self, year=None, month=None, retry=3, pause=0.001):
232 | """
233 | 获取限售股解禁数据
234 | Parameters
235 | --------
236 | year:年份,默认为当前年
237 | month:解禁月份,默认为当前月
238 | retry : int, 默认 3
239 | 如遇网络等问题重复执行的次数
240 | pause : int, 默认 0
241 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
242 |
243 | Return
244 | ------
245 | DataFrame or List: [{'code':, 'name':, ...}, ...]
246 | code:股票代码
247 | name:名称
248 | date:解禁日期
249 | count:解禁数量(万股)
250 | ratio:占总盘比率
251 | """
252 | self._data = pd.DataFrame()
253 |
254 | year = Utility.getYear() if year is None else year
255 | month = Utility.getMonth() if month is None else month
256 |
257 | for _ in range(retry):
258 | time.sleep(pause)
259 |
260 | try:
261 | # http://datainterface.eastmoney.com/EM_DataCenter/JS.aspx?type=FD&sty=BST&st=3&sr=true&fd=2019&stat=1
262 | request = self._session.get( cf.RL_URL % (year, month), timeout = 10 )
263 | if self._PY3:
264 | request.encoding = 'utf-8'
265 | lines = request.text
266 | except Exception as e:
267 | print(e)
268 | else:
269 | da = lines[3:len(lines)-3]
270 | list = []
271 | for row in da.split('","'):
272 | list.append([data for data in row.split(',')])
273 | self._data = pd.DataFrame(list)
274 | self._data = self._data[[1, 3, 4, 5, 6]]
275 | for col in [5, 6]:
276 | self._data[col] = self._data[col].astype(float)
277 | self._data[5] = self._data[5]/10000
278 | self._data[6] = self._data[6]*100
279 | self._data[5] = self._data[5].map(cf.FORMAT)
280 | self._data[6] = self._data[6].map(cf.FORMAT)
281 | self._data.columns = cf.RL_COLS
282 |
283 | return self._result()
284 |
285 | raise IOError(cf.NETWORK_URL_ERROR_MSG)
286 |
287 |
288 | def fundHoldings(self, year, quarter, retry=3, pause=0.001):
289 | """
290 | 获取基金持股数据
291 | Parameters
292 | --------
293 | year:年份e.g 2014
294 | quarter:季度(只能输入1,2,3,4这个四个数字)
295 | retry : int, 默认 3
296 | 如遇网络等问题重复执行的次数
297 | pause : int, 默认 0
298 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
299 |
300 | Return
301 | ------
302 | DataFrame or List: [{'code':, 'name':, ...}, ...]
303 | code:股票代码
304 | name:名称
305 | date:报告日期
306 | nums:基金家数
307 | nlast:与上期相比(增加或减少了)
308 | count:基金持股数(万股)
309 | clast:与上期相比
310 | amount:基金持股市值
311 | ratio:占流通盘比率
312 | """
313 | self._data = pd.DataFrame()
314 |
315 | start, end = cf.QUARTS_DIC[str(quarter)]
316 | if quarter == 1:
317 | start = start % str(year-1)
318 | end = end % year
319 | else:
320 | start, end = start % year, end % year
321 |
322 | self._writeHead()
323 |
324 | self._data, pages = self.__handleFoundHoldings(start, end, 0, retry, pause)
325 | for idx in range(1, pages):
326 | self._data = self._data.append(self.__handleFoundHoldings(start, end, idx, retry, pause), ignore_index=True)
327 |
328 | return self._result()
329 |
330 |
331 | def __handleFoundHoldings(self, start, end, pageNo, retry, pause):
332 | for _ in range(retry):
333 | time.sleep(pause)
334 | if pageNo>0:
335 | self._writeConsole()
336 | try:
337 | # http://quotes.money.163.com/hs/marketdata/service/jjcgph.php?host=/hs/marketdata/service/jjcgph.php&page=0&query=start:2018-06-30;end:2018-09-30&order=desc&count=60&type=query&req=73259
338 | request = self._session.get( cf.FUND_HOLDS_URL % (pageNo, start, end, Utility.random(5)), timeout=10 )
339 | if self._PY3:
340 | request.encoding = 'utf-8'
341 | lines = request.text
342 | lines = lines.replace('--', '0')
343 | lines = json.loads(lines)
344 | data = lines['list']
345 | df = pd.DataFrame(data)
346 | df = df.drop(['CODE', 'ESYMBOL', 'EXCHANGE', 'NAME', 'RN', 'SHANGQIGUSHU', 'SHANGQISHIZHI', 'SHANGQISHULIANG'], axis=1)
347 | for col in ['GUSHU', 'GUSHUBIJIAO', 'SHIZHI', 'SCSTC27']:
348 | df[col] = df[col].astype(float)
349 | df['SCSTC27'] = df['SCSTC27']*100
350 | df['GUSHU'] = df['GUSHU']/10000
351 | df['GUSHUBIJIAO'] = df['GUSHUBIJIAO']/10000
352 | df['SHIZHI'] = df['SHIZHI']/10000
353 | df['GUSHU'] = df['GUSHU'].map(cf.FORMAT)
354 | df['GUSHUBIJIAO'] = df['GUSHUBIJIAO'].map(cf.FORMAT)
355 | df['SHIZHI'] = df['SHIZHI'].map(cf.FORMAT)
356 | df['SCSTC27'] = df['SCSTC27'].map(cf.FORMAT)
357 | df.columns = cf.FUND_HOLDS_COLS
358 | df = df[['code', 'name', 'date', 'nums', 'nlast', 'count',
359 | 'clast', 'amount', 'ratio']]
360 | except Exception as e:
361 | print(e)
362 | else:
363 | if pageNo == 0:
364 | return df, int(lines['pagecount'])
365 | else:
366 | return df
367 |
368 | raise IOError(cf.NETWORK_URL_ERROR_MSG)
369 |
370 |
371 | def ipo(self, retry=3, pause=0.001):
372 | """
373 | 获取新股上市数据
374 | Parameters
375 | --------
376 | retry : int, 默认 3
377 | 如遇网络等问题重复执行的次数
378 | pause : int, 默认 0
379 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
380 |
381 | Return
382 | ------
383 | DataFrame or List: [{'code':, 'name':, ...}, ...]
384 | code:股票代码
385 | xcode:申购代码
386 | name:名称
387 | ipo_date:上网发行日期
388 | issue_date:上市日期
389 | amount:发行数量(万股)
390 | markets:上网发行数量(万股)
391 | price:发行价格(元)
392 | pe:发行市盈率
393 | limit:个人申购上限(万股)
394 | funds:募集资金(亿元)
395 | ballot:网上中签率(%)
396 | """
397 | self._data = pd.DataFrame()
398 |
399 | self._writeHead()
400 |
401 | self._data = self.__handleIpo(self._data, 1, retry, pause)
402 |
403 | return self._result()
404 |
405 |
406 | def __handleIpo(self, data, pageNo, retry, pause):
407 | self._writeConsole()
408 |
409 | for _ in range(retry):
410 | time.sleep(pause)
411 |
412 | try:
413 | # http://vip.stock.finance.sina.com.cn/corp/view/vRPD_NewStockIssue.php?page=1&cngem=0&orderBy=NetDate&orderType=desc
414 | html = lxml.html.parse(cf.NEW_STOCKS_URL % pageNo)
415 | res = html.xpath('//table[@id=\"NewStockTable\"]/tr')
416 | if not res:
417 | return data
418 |
419 | if self._PY3:
420 | sarr = [etree.tostring(node).decode('utf-8') for node in res]
421 | else:
422 | sarr = [etree.tostring(node) for node in res]
423 | sarr = ''.join(sarr)
424 | sarr = sarr.replace('*', '')
425 | sarr = ''%sarr
426 | df = pd.read_html(StringIO(sarr), skiprows=[0, 1])[0]
427 | df = df.drop([df.columns[idx] for idx in [12, 13, 14]], axis=1)
428 | df.columns = cf.NEW_STOCKS_COLS
429 | df['code'] = df['code'].map(lambda x : str(x).zfill(6))
430 | df['xcode'] = df['xcode'].map(lambda x : str(x).zfill(6))
431 | res = html.xpath('//table[@class=\"table2\"]/tr[1]/td[1]/a/text()')
432 | tag = '下一页' if self._PY3 else unicode('下一页', 'utf-8')
433 | hasNext = True if tag in res else False
434 | data = data.append(df, ignore_index=True)
435 | pageNo += 1
436 | if hasNext:
437 | data = self.__handleIpo(data, pageNo, retry, pause)
438 | except Exception as ex:
439 | print(ex)
440 | else:
441 | return data
442 |
443 |
444 | def shMargins(self, retry=3, pause=0.001):
445 | """
446 | 沪市融资融券历史数据
447 | Parameters
448 | --------
449 | retry : int, 默认 3
450 | 如遇网络等问题重复执行的次数
451 | pause : int, 默认 0
452 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
453 |
454 | Return
455 | ------
456 | DataFrame or List: [{'date':, 'close':, ...}, ...]
457 | date: 日期
458 | close: 上证指数收盘点数
459 | zdf: 上证指数收盘涨跌幅(%)
460 | rzye: 融资余额(元)
461 | rzyezb: 融资余额占比(%)
462 | rzmre: 融资买入额(元)
463 | rzche: 融资偿还额(元)
464 | rzjmre: 融资净买入额(元)
465 | rqye: 融券余额(元)
466 | rqyl: 融券余量(股)
467 | rqmcl: 融券卖出量(股)
468 | rqchl: 融券偿还量(股)
469 | rqjmcl: 融券净卖出量(股)
470 | rzrqye: 融资融券余额(元)
471 | rzrqyecz: 融资融券余额差值(元)
472 | """
473 | self._data = pd.DataFrame()
474 |
475 | self._writeHead()
476 |
477 | self._data = self.__handleMargins(self._data, 1, 'SH', Utility.random(8), cf.MAR_COLS, retry, pause)
478 | self._data.rename(columns={'tdate':'date'}, inplace=True)
479 |
480 | return self._result()
481 |
482 |
483 | def szMargins(self, retry=3, pause=0.001):
484 | """
485 | 深市融资融券历史数据
486 | Parameters
487 | --------
488 | retry : int, 默认 3
489 | 如遇网络等问题重复执行的次数
490 | pause : int, 默认 0
491 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
492 |
493 | Return
494 | ------
495 | DataFrame or List: [{'date':, 'close':, ...}, ...]
496 | date: 日期
497 | close: 深证成指收盘点数
498 | zdf: 深证成指收盘涨跌幅(%)
499 | rzye: 融资余额(元)
500 | rzyezb: 融资余额占比(%)
501 | rzmre: 融资买入额(元)
502 | rzche: 融资偿还额(元)
503 | rzjmre: 融资净买入额(元)
504 | rqye: 融券余额(元)
505 | rqyl: 融券余量(股)
506 | rqmcl: 融券卖出量(股)
507 | rqchl: 融券偿还量(股)
508 | rqjmcl: 融券净卖出量(股)
509 | rzrqye: 融资融券余额(元)
510 | rzrqyecz: 融资融券余额差值(元)
511 | """
512 | self._data = pd.DataFrame()
513 |
514 | self._writeHead()
515 |
516 | self._data = self.__handleMargins(self._data, 1, 'SZ', Utility.random(8), cf.MAR_COLS, retry, pause)
517 | self._data.rename(columns={'tdate':'date'}, inplace=True)
518 |
519 | return self._result()
520 |
521 |
522 | def __handleMargins(self, dataArr, page, market, randInt, column, retry, pause):
523 | self._writeConsole()
524 |
525 | for _ in range(retry):
526 | time.sleep(pause)
527 |
528 | try:
529 | request = self._session.get( cf.MAR_URL % (page, market, randInt) )
530 | text = request.text.split('=')[1]
531 | text = text.replace('{pages:', '{"pages":').replace(',data:', ',"data":').replace('T00:00:00', '').replace('"-"', '0')
532 | dataDict = Utility.str2Dict(text)
533 | data = dataDict['data']
534 | df = pd.DataFrame(data, columns=column)
535 |
536 | df['close'] = df['close'].map(cf.FORMAT)
537 | df['rzyezb'] = df['rzyezb'].astype(float)
538 |
539 | dataArr = dataArr.append(df, ignore_index=True)
540 | if page < dataDict['pages']:
541 | dataArr = self.__handleMargins(dataArr, page+1, market, randInt, column, retry, pause)
542 | except Exception as e:
543 | print(e)
544 | else:
545 | return dataArr
546 |
547 | raise IOError(cf.NETWORK_URL_ERROR_MSG)
548 |
549 |
550 | def marginDetailsAllByDate(self, date, retry=3, pause=0.001):
551 | """
552 | 按日期获取两市融资融券明细列表
553 | Parameters
554 | --------
555 | date : string
556 | 选择日期 format:YYYY-MM-DD
557 | retry : int, 默认 3
558 | 如遇网络等问题重复执行的次数
559 | pause : int, 默认 0
560 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
561 |
562 | Return
563 | ------
564 | DataFrame or List: [{'code':, 'name':, ...}, ...]
565 | code: 股票代码
566 | name: 名称
567 | rzye: 当日融资余额(元)
568 | rzyezb: 当日融资余额占比(%)
569 | rzmre: 当日融资买入额(元)
570 | rzche: 当日融资偿还额(元)
571 | rzjmre: 当日融资净买入额(元)
572 | rqye: 当日融券余额(元)
573 | rqyl: 当日融券余量(股)
574 | rqmcl: 当日融券卖出量(股)
575 | rqchl: 当日融券偿还量(股)
576 | rqjmcl: 当日融券净卖出量(股)
577 | rzrqye: 当日融资融券余额(元)
578 | rzrqyecz: 当日融资融券余额差值(元)
579 | """
580 | self._data = pd.DataFrame()
581 |
582 | self._writeHead()
583 |
584 | self._data = self.__handleMarginDetailsAllByDate(self._data, date, 1, Utility.random(8), retry, pause)
585 | self._data.rename(columns={'scode':'code', 'sname':'name'}, inplace=True)
586 |
587 | return self._result()
588 |
589 |
590 | def __handleMarginDetailsAllByDate(self, dataArr, date, page, randInt, retry, pause):
591 | self._writeConsole()
592 |
593 | for _ in range(retry):
594 | time.sleep(pause)
595 |
596 | try:
597 | request = self._session.get(cf.MAR_BOTH_DETAIL % (date, page, randInt))
598 | text = request.text.split('=')[1]
599 | text = text.replace('{pages:', '{"pages":').replace(',data:', ',"data":').replace('"-"', '0')
600 | dataDict = Utility.str2Dict(text)
601 | data = dataDict['data']
602 | df = pd.DataFrame(data, columns=cf.MAR_DET_All_COLS)
603 |
604 | df['date'] = date
605 | df['rzyezb'] = df['rzyezb'].astype(float)
606 |
607 | dataArr = dataArr.append(df, ignore_index=True)
608 | if page < dataDict['pages']:
609 | dataArr = self.__handleMarginDetailsAllByDate(dataArr, date, page+1, randInt, retry, pause)
610 | except Exception as e:
611 | print(e)
612 | else:
613 | return dataArr
614 |
615 | raise IOError(cf.NETWORK_URL_ERROR_MSG)
616 |
617 |
618 | def marginTotal(self, retry=3, pause=0.001):
619 | """
620 | 两市合计融资融券历史数据
621 | Parameters
622 | --------
623 | retry : int, 默认 3
624 | 如遇网络等问题重复执行的次数
625 | pause : int, 默认 0
626 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
627 |
628 | Return
629 | ------
630 | DataFrame or List: [{'date':, 'close':, ...}, ...]
631 | date: 日期
632 | close: 沪深300收盘点数
633 | zdf: 沪深300收盘涨跌幅(%)
634 | rzye: 融资余额(元)
635 | rzyezb: 融资余额占比(%)
636 | rzmre: 融资买入额(元)
637 | rzche: 融资偿还额(元)
638 | rzjmre: 融资净买入额(元)
639 | rqye: 融券余额(元)
640 | rqyl: 融券余量(股)
641 | rqmcl: 融券卖出量(股)
642 | rqchl: 融券偿还量(股)
643 | rqjmcl: 融券净卖出量(股)
644 | rzrqye: 融资融券余额(元)
645 | rzrqyecz: 融资融券余额差值(元)
646 | """
647 | self._data = pd.DataFrame()
648 |
649 | self._writeHead()
650 |
651 | self._data = self.__handleMarginTotal(self._data, 1, Utility.random(8), retry, pause)
652 | self._data.rename(columns={'tdate':'date'}, inplace=True)
653 |
654 | return self._result()
655 |
656 |
657 | def __handleMarginTotal(self, dataArr, page, randInt, retry, pause):
658 | self._writeConsole()
659 |
660 | for _ in range(retry):
661 | time.sleep(pause)
662 |
663 | try:
664 | request = self._session.get(cf.MAR_TOTAL_URL % (page, randInt), timeout=10)
665 | text = request.text.split('=')[1]
666 | text = text.replace('{pages:', '{"pages":').replace(',data:', ',"data":').replace('T00:00:00', '').replace('"-"', '0')
667 | dataDict = Utility.str2Dict(text)
668 | data = dataDict['data']
669 | df = pd.DataFrame(data, columns=cf.MAR_TOTAL_COLS)
670 |
671 | df['close'] = df['close'].map(cf.FORMAT)
672 | df['rzyezb'] = df['rzyezb'].astype(float)
673 |
674 | dataArr = dataArr.append(df, ignore_index=True)
675 | if page < dataDict['pages']:
676 | dataArr = self.__handleMarginTotal(dataArr, page+1, randInt, retry, pause)
677 | except Exception as e:
678 | print(e)
679 | else:
680 | return dataArr
681 |
682 | raise IOError(cf.NETWORK_URL_ERROR_MSG)
683 |
684 |
--------------------------------------------------------------------------------
/GuGu/stockdata.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | """
3 | 股票交易类
4 | Created on 2018/12/26
5 | @author: TabQ
6 | @group : GuGu
7 | @contact: 16621596@qq.com
8 | """
9 | from __future__ import division
10 |
11 | import time
12 | import json
13 | import re
14 | import lxml.html
15 | from lxml import etree
16 | import pandas as pd
17 | from pandas.compat import StringIO
18 | from base import Base, cf
19 | from utility import Utility
20 |
21 | class StockData(Base):
22 | def __init__(self, code=None, pandas=True, inter=True):
23 | Base.__init__(self, pandas, inter)
24 | self.__code = code
25 |
26 |
27 | def history(self, start='', end='', ktype='D', autype='qfq', index=False, retry=3, pause=0.001):
28 | """
29 | 获取股票交易历史数据
30 | ---------
31 | Parameters:
32 | start:string
33 | 开始日期 format:YYYY-MM-DD 为空时取上市首日
34 | end:string
35 | 结束日期 format:YYYY-MM-DD 为空时取最近一个交易日
36 | autype:string
37 | 复权类型,qfq-前复权 hfq-后复权 None-不复权,默认为qfq
38 | ktype:string
39 | 数据类型,D=日k线 W=周 M=月 5=5分钟 15=15分钟 30=30分钟 60=60分钟,默认为D
40 | retry: int, 默认 3
41 | 如遇网络等问题重复执行的次数
42 | pause : int, 默认 0
43 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
44 | return
45 | -------
46 | DataFrame or list: [{'date':, 'open':, ...}, ...]
47 | date 交易日期 (index)
48 | open 开盘价
49 | high 最高价
50 | close 收盘价
51 | low 最低价
52 | volume 成交量
53 | code 股票代码
54 | """
55 | self._data = pd.DataFrame()
56 |
57 | url = ''
58 | dataflag = ''
59 | symbol = cf.INDEX_SYMBOL[self.__code] if index else Utility.symbol(self.__code)
60 | autype = '' if autype is None else autype
61 |
62 | if (start is not None) & (start != ''):
63 | end = Utility.getToday() if end is None or end == '' else end
64 |
65 | if ktype.upper() in cf.K_LABELS:
66 | fq = autype if autype is not None else ''
67 | if self.__code[:1] in ('1', '5') or index:
68 | fq = ''
69 |
70 | kline = '' if autype is None else 'fq'
71 | if (start is None or start == '') & (end is None or end == ''):
72 | # http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_dayqfq¶m=sh600000,day,,,640,qfq&r=0.73327461855388564
73 | urls = [cf.HISTORY_URL % (kline, fq, symbol, cf.TT_K_TYPE[ktype.upper()], start, end, fq, Utility.random(17))]
74 | else:
75 | years = Utility.ttDates(start, end)
76 | urls = []
77 | for year in years:
78 | startdate = str(year) + '-01-01'
79 | enddate = str(year+1) + '-12-31'
80 | # http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_dayqfq2008¶m=sh600000,day,2008-01-01,2009-12-31,640,qfq&r=0.73327461855388564
81 | url = cf.HISTORY_URL % (kline, fq+str(year), symbol, cf.TT_K_TYPE[ktype.upper()], startdate, enddate, fq, Utility.random(17))
82 | urls.append(url)
83 | dataflag = '%s%s'%(fq, cf.TT_K_TYPE[ktype.upper()]) # qfqday
84 | elif ktype in cf.K_MIN_LABELS:
85 | # http://ifzq.gtimg.cn/appstock/app/kline/mkline?param=sh600000,m30,,640&_var=m30_today&r=0.5537154641907898
86 | urls = [cf.HISTORY_MIN_URL % (symbol, ktype, ktype, Utility.random(16))]
87 | dataflag = 'm%s'%ktype # m30
88 | else:
89 | raise TypeError('ktype input error.')
90 |
91 | for url in urls:
92 | self._data = self._data.append(self.__handleHistory(url, dataflag, symbol, index, ktype, retry, pause), ignore_index=True)
93 | if ktype not in cf.K_MIN_LABELS:
94 | if ((start is not None) & (start != '')) & ((end is not None) & (end != '')):
95 | self._data = self._data[(self._data.date >= start) & (self._data.date <= end)]
96 |
97 | return self._result()
98 |
99 | raise IOError(cf.NETWORK_URL_ERROR_MSG)
100 |
101 |
102 | def __handleHistory(self, url, dataflag='', symbol='', index = False, ktype = '', retry=3, pause=0.001):
103 | for _ in range(retry):
104 | time.sleep(pause)
105 |
106 | try:
107 | request = self._session.get(url, timeout=10)
108 | if self._PY3:
109 | request.encoding = 'gbk'
110 | lines = request.text
111 | if len(lines) < 100: #no data
112 | return None
113 | except Exception as e:
114 | print(e)
115 | else:
116 | lines = lines.split('=')[1]
117 | reg = re.compile(r',{"nd.*?}')
118 | lines = re.subn(reg, '', lines)
119 | js = json.loads(lines[0])
120 | dataflag = dataflag if dataflag in list(js['data'][symbol].keys()) else cf.TT_K_TYPE[ktype.upper()]
121 |
122 | if ktype in cf.K_MIN_LABELS:
123 | for value in js['data'][symbol][dataflag]:
124 | value.pop()
125 | value.pop()
126 |
127 | df = pd.DataFrame(js['data'][symbol][dataflag], columns=cf.KLINE_TT_COLS)
128 | df['code'] = symbol if index else self.__code
129 | if ktype in cf.K_MIN_LABELS:
130 | df['date'] = df['date'].map(lambda x: '%s-%s-%s %s:%s'%(x[0:4], x[4:6], x[6:8], x[8:10], x[10:12]))
131 | for col in df.columns[1:6]:
132 | df[col] = df[col].astype(float)
133 |
134 | return df
135 |
136 |
137 | def xrxd(self, date='', retry=3, pause=0.001):
138 | """
139 | 获取股票除权除息信息
140 | Parameters
141 | ------
142 | date: string
143 | format:YYYY-MM-DD
144 | retry: int, 默认 3
145 | 如遇网络等问题重复执行的次数
146 | pause : int, 默认 0
147 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
148 |
149 | return
150 | ------
151 | Dict or None
152 | nd, 对应年份
153 | fh_sh, 分红数额
154 | djr, 股权登记日
155 | cqr, 除权日
156 | FHcontent, 除权除息信息
157 | """
158 | data = None
159 |
160 | if not date:
161 | date = Utility.getToday()
162 |
163 | symbol = Utility.symbol(self.__code)
164 |
165 | for _ in range(retry):
166 | time.sleep(pause)
167 |
168 | url = cf.HISTORY_URL % ('fq', 'qfq', symbol, 'day', date, date, 'qfq', Utility.random(17))
169 | try:
170 | request = self._session.get(url, timeout=10)
171 | pattern = re.compile(r'({"nd".+?})')
172 | result = re.search(pattern, request.text)
173 | if result:
174 | data = eval(result.group(1))
175 | except Exception as e:
176 | print(str(e))
177 |
178 | return data
179 |
180 | raise IOError(cf.NETWORK_URL_ERROR_MSG)
181 |
182 |
183 | def realtime(self):
184 | """
185 | 获取实时交易数据 getting real time quotes data
186 | 用于跟踪交易情况(本次执行的结果-上一次执行的数据)
187 | Parameters
188 | ------
189 | stockdata(code) code : string, array-like object (list, tuple, Series).
190 | return
191 | -------
192 | DataFrame 实时交易数据 or list: [{'name':, 'open':, ...}, ...]
193 | 属性:0:name,股票名字
194 | 1:open,今日开盘价
195 | 2:pre_close,昨日收盘价
196 | 3:price,当前价格
197 | 4:high,今日最高价
198 | 5:low,今日最低价
199 | 6:bid,竞买价,即“买一”报价
200 | 7:ask,竞卖价,即“卖一”报价
201 | 8:volumn,成交量 maybe you need do volumn/100
202 | 9:amount,成交金额(元 CNY)
203 | 10:b1_v,委买一(笔数 bid volume)
204 | 11:b1_p,委买一(价格 bid price)
205 | 12:b2_v,“买二”
206 | 13:b2_p,“买二”
207 | 14:b3_v,“买三”
208 | 15:b3_p,“买三”
209 | 16:b4_v,“买四”
210 | 17:b4_p,“买四”
211 | 18:b5_v,“买五”
212 | 19:b5_p,“买五”
213 | 20:a1_v,委卖一(笔数 ask volume)
214 | 21:a1_p,委卖一(价格 ask price)
215 | ...
216 | 30:date,日期;
217 | 31:time,时间;
218 | """
219 | self._data = pd.DataFrame()
220 |
221 | symbols_list = ''
222 | if isinstance(self.__code, list) or isinstance(self.__code, set) or isinstance(self.__code, tuple) or isinstance(self.__code, pd.Series):
223 | for code in self.__code:
224 | symbols_list += Utility.symbol(code) + ','
225 | else:
226 | symbols_list = Utility.symbol(self.__code)
227 | symbols_list = symbols_list[:-1] if len(symbols_list) > 8 else symbols_list
228 |
229 | # http://hq.sinajs.cn/rn=4879967949085&list=sh600000,sh600004
230 | request = self._session.get( cf.LIVE_DATA_URL % (Utility.random(), symbols_list), timeout=10 )
231 | request.encoding = 'gbk'
232 | reg = re.compile(r'\="(.*?)\";')
233 | data = reg.findall(request.text)
234 | regSym = re.compile(r'(?:sh|sz)(.*?)\=')
235 | syms = regSym.findall(request.text)
236 | data_list = []
237 | syms_list = []
238 | for index, row in enumerate(data):
239 | if len(row)>1:
240 | data_list.append([astr for astr in row.split(',')])
241 | syms_list.append(syms[index])
242 | if len(syms_list) == 0:
243 | return None
244 |
245 | self._data = pd.DataFrame(data_list, columns=cf.LIVE_DATA_COLS)
246 | self._data = self._data.drop('s', axis=1)
247 | self._data['code'] = syms_list
248 | ls = [cls for cls in self._data.columns if '_v' in cls]
249 | for txt in ls:
250 | self._data[txt] = self._data[txt].map(lambda x : x[:-2])
251 |
252 | return self._result()
253 |
254 |
255 | def historyTicks(self, date=None, retry=3, pause=0.001):
256 | """
257 | 获取历史分笔明细数据
258 | Parameters
259 | ------
260 | date : string
261 | 日期 format:YYYY-MM-DD, 默认为前一个交易日
262 | retry : int, 默认 3
263 | 如遇网络等问题重复执行的次数
264 | pause : int, 默认 0
265 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
266 | return
267 | -------
268 | DataFrame 当日所有股票交易数据(DataFrame) or list: [{'time':, 'price':, ...}, ...]
269 | 属性:成交时间、成交价格、价格变动,成交手、成交金额(元),买卖类型
270 | """
271 | self._data = pd.DataFrame()
272 |
273 | symbol = Utility.symbol(self.__code)
274 | date = Utility.lastTradeDate() if date is None else date
275 |
276 | try:
277 | self._writeHead()
278 |
279 | page = 1
280 | while(True):
281 | # http://vip.stock.finance.sina.com.cn/quotes_service/view/vMS_tradehistory.php?symbol=sh600000&date=2018-12-26&page=1
282 | # http://market.finance.sina.com.cn/transHis.php?date=2019-01-25&symbol=sh600000&page=1
283 | url = cf.HISTORY_TICKS_URL % (date, symbol, page)
284 | tick_data = self.__handleTicks(url, cf.HISTORY_TICK_COLUMNS, retry, pause)
285 | if tick_data is not None:
286 | self._data = self._data.append(tick_data, ignore_index=True)
287 | page = page + 1
288 | else:
289 | break
290 | except Exception as er:
291 | print(str(er))
292 | else:
293 | return self._result()
294 |
295 | raise IOError(cf.NETWORK_URL_ERROR_MSG)
296 |
297 |
298 | def __handleTicks(self, url, column, retry, pause):
299 | self._writeConsole()
300 |
301 | for _ in range(retry):
302 | time.sleep(pause)
303 |
304 | try:
305 | html = lxml.html.parse(url)
306 | res = html.xpath('//table[@id=\"datatbl\"]/tbody/tr')
307 | if not res:
308 | return None
309 |
310 | if self._PY3:
311 | sarr = [etree.tostring(node).decode('utf-8') for node in res]
312 | else:
313 | sarr = [etree.tostring(node) for node in res]
314 | sarr = ''.join(sarr)
315 | sarr = ''%sarr
316 | sarr = sarr.replace('--', '0')
317 | df = pd.read_html(StringIO(sarr), parse_dates=False)
318 | df = pd.read_html(StringIO(sarr), parse_dates=False)[0]
319 | df.columns = column
320 | if 'pchange' in column:
321 | df['pchange'] = df['pchange'].map(lambda x : x.replace('%', ''))
322 | except Exception as e:
323 | print(e)
324 | else:
325 | return df
326 |
327 | raise IOError(cf.NETWORK_URL_ERROR_MSG)
328 |
329 | def todayTicks(self, retry=3, pause=0.001):
330 | """
331 | 获取当日分笔明细数据
332 | Parameters
333 | ------
334 | retry : int, 默认 3
335 | 如遇网络等问题重复执行的次数
336 | pause : int, 默认 0
337 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
338 | return
339 | -------
340 | DataFrame 当日所有股票交易数据(DataFrame) or list: [{'time':, 'price':, ...}, ...]
341 | 属性:成交时间、成交价格、涨跌幅、价格变动,成交手、成交金额(元),买卖类型
342 | """
343 | self._data = pd.DataFrame()
344 |
345 | if self.__code is None or len(self.__code)!=6 :
346 | return None
347 |
348 | if not Utility.isTradeDay():
349 | return None
350 |
351 | # 不到交易时间
352 | openTime = time.mktime(time.strptime(Utility.getToday() + ' 09:25:00', '%Y-%m-%d %H:%M:%S'))
353 | now = time.time()
354 | if now < openTime:
355 | return None
356 |
357 | symbol = Utility.symbol(self.__code)
358 | date = Utility.getToday()
359 |
360 | for _ in range(retry):
361 | time.sleep(pause)
362 |
363 | try:
364 | # http://vip.stock.finance.sina.com.cn/quotes_service/api/json_v2.php/CN_Transactions.getAllPageTime?date=2018-12-26&symbol=sh600000
365 | request = self._session.get( cf.TODAY_TICKS_PAGE_URL % (date, symbol), timeout=10 )
366 | request.encoding = 'gbk'
367 | text = request.text[1:-1]
368 | data_dict = Utility.str2Dict(text)
369 | pages = len(data_dict['detailPages'])
370 |
371 | self._writeHead()
372 | for pNo in range(1, pages+1):
373 | # http://vip.stock.finance.sina.com.cn/quotes_service/view/vMS_tradedetail.php?symbol=sh600000&date=2018-12-26&page=1
374 | url = cf.TODAY_TICKS_URL % (symbol, date, pNo)
375 | self._data = self._data.append(self.__handleTicks(url, cf.TODAY_TICK_COLUMNS, retry, pause), ignore_index=True)
376 | except Exception as e:
377 | print(str(e))
378 | else:
379 | return self._result()
380 |
381 | raise IOError(cf.NETWORK_URL_ERROR_MSG)
382 |
383 |
384 | def bigDeal(self, date=None, vol=400, retry=3, pause=0.001):
385 | """
386 | 获取大单数据
387 | Parameters
388 | ------
389 | date:string
390 | 日期 format:YYYY-MM-DD
391 | retry : int, 默认 3
392 | 如遇网络等问题重复执行的次数
393 | pause : int, 默认 0
394 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
395 | return
396 | -------
397 | DataFrame 当日所有股票交易数据(DataFrame) or list: [{'code':, 'name', ...}, ...]
398 | 属性:股票代码 股票名称 交易时间 价格 成交量 前一笔价格 类型(买、卖、中性盘)
399 | """
400 | self._data = pd.DataFrame()
401 |
402 | if self.__code is None or len(self.__code) != 6 or date is None:
403 | return None
404 |
405 | symbol = Utility.symbol(self.__code)
406 | vol = vol*100
407 |
408 | for _ in range(retry):
409 | time.sleep(pause)
410 |
411 | try:
412 | # http://vip.stock.finance.sina.com.cn/quotes_service/view/cn_bill_download.php?symbol=sh600000&num=60&page=1&sort=ticktime&asc=0&volume=40000&amount=0&type=0&day=2018-12-26
413 | request = self._session.get( cf.SINA_DD % (symbol, vol, date), timeout=10 )
414 | request.encoding = 'gbk'
415 | lines = request.text
416 | if len(lines) < 100:
417 | return None
418 | self._data = pd.read_csv(StringIO(lines), names=cf.SINA_DD_COLS, skiprows=[0])
419 | if self._data is not None:
420 | self._data['code'] = self._data['code'].map(lambda x: x[2:])
421 | except Exception as e:
422 | print(e)
423 | else:
424 | return self._result()
425 |
426 | raise IOError(cf.NETWORK_URL_ERROR_MSG)
427 |
428 |
429 |
--------------------------------------------------------------------------------
/GuGu/stockinfo.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | """
3 | 股票信息类
4 | Created on 2019/01/02
5 | @author: TabQ
6 | @group : GuGu
7 | @contact: 16621596@qq.com
8 | """
9 | from __future__ import division
10 |
11 | import time
12 | import pandas as pd
13 | from pandas.compat import StringIO
14 | import lxml.html
15 | from lxml import etree
16 | import re
17 | from utility import Utility
18 | from base import Base, cf
19 |
20 | class StockInfo(Base):
21 | def stockProfiles(self, retry=3, pause=0.001):
22 | """
23 | 获取上市公司基本情况
24 | Parameters
25 | --------
26 | retry : int, 默认 3
27 | 如遇网络等问题重复执行的次数
28 | pause : int, 默认 0
29 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
30 |
31 | Return
32 | --------
33 | DataFrame or List: [{'code':, 'name':, ...}, ...]
34 | code,代码
35 | name,名称
36 | city,所在城市
37 | staff,员工人数
38 | date,上市日期
39 | industry,行业分类
40 | pro_type,产品类型
41 | main,主营业务
42 | """
43 | self._data = pd.DataFrame()
44 |
45 | self._writeHead()
46 |
47 | date = '%s-12-31' % Utility.getYear()
48 | self._data = pd.DataFrame()
49 |
50 | self._data = self.__handleStockProfiles(self._data, date, 1, retry, pause)
51 |
52 | return self._result()
53 |
54 |
55 | def __handleStockProfiles(self, dataArr, date, page, retry, pause):
56 | self._writeConsole()
57 |
58 | for _ in range(retry):
59 | time.sleep(pause)
60 |
61 | try:
62 | html = lxml.html.parse(cf.ALL_STOCK_PROFILES_URL % (date, page))
63 | res = html.xpath('//table[@id="myTable04"]/tbody/tr')
64 | if not res:
65 | return dataArr
66 |
67 | if self._PY3:
68 | sarr = [etree.tostring(node).decode('utf-8') for node in res]
69 | else:
70 | sarr = [etree.tostring(node) for node in res]
71 | sarr = ''.join(sarr)
72 | sarr = '' % sarr
73 |
74 | df = pd.read_html(sarr)[0]
75 | df = df.drop([0, 3, 5, 6, 7, 10, 11], axis = 1)
76 | df.columns = cf.ALL_STOCK_PROFILES_COLS
77 | df['code'] = df['code'].map(lambda x: str(x).zfill(6))
78 |
79 | dataArr = dataArr.append(df, ignore_index=True)
80 | except Exception as e:
81 | print(e)
82 | else:
83 | return self.__handleStockProfiles(dataArr, date, page+1, retry, pause)
84 |
85 |
86 | def report(self, year, quarter, retry=3, pause=0.001):
87 | """
88 | 获取业绩报表数据
89 | Parameters
90 | --------
91 | year:int 年度 e.g:2014
92 | quarter:int 季度 :1、2、3、4,只能输入这4个季度
93 | 说明:由于是从网站获取的数据,需要一页页抓取,速度取决于您当前网络速度
94 | retry : int, 默认 3
95 | 如遇网络等问题重复执行的次数
96 | pause : int, 默认 0.001
97 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
98 | Return
99 | --------
100 | DataFrame or List: [{'code':, 'name':, ...}, ...]
101 | code,代码
102 | name,名称
103 | eps,每股收益
104 | eps_yoy,每股收益同比(%)
105 | bvps,每股净资产
106 | roe,净资产收益率(%)
107 | epcf,每股现金流量(元)
108 | net_profits,净利润(万元)
109 | profits_yoy,净利润同比(%)
110 | distrib,分配方案
111 | report_date,发布日期
112 | """
113 | self._data = pd.DataFrame()
114 |
115 | if Utility.checkQuarter(year, quarter) is True:
116 | self._writeHead()
117 |
118 | # http://vip.stock.finance.sina.com.cn/q/go.php/vFinanceAnalyze/kind/mainindex/index.phtml?s_i=&s_a=&s_c=&reportdate=2018&quarter=3&p=1&num=60
119 | self._data = self.__parsePage(cf.REPORT_URL, year, quarter, 1, cf.REPORT_COLS, pd.DataFrame(), retry, pause, 11)
120 | if self._data is not None:
121 | self._data['code'] = self._data['code'].map(lambda x:str(x).zfill(6))
122 |
123 | return self._result()
124 |
125 | def profit(self, year, quarter, retry=3, pause=0.001):
126 | """
127 | 获取盈利能力数据
128 | Parameters
129 | --------
130 | year:int 年度 e.g:2014
131 | quarter:int 季度 :1、2、3、4,只能输入这4个季度
132 | 说明:由于是从网站获取的数据,需要一页页抓取,速度取决于您当前网络速度
133 | retry : int, 默认 3
134 | 如遇网络等问题重复执行的次数
135 | pause : int, 默认 0.001
136 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
137 | Return
138 | --------
139 | DataFrame or List: [{'code':, 'name':, ...}, ...]
140 | code,代码
141 | name,名称
142 | roe,净资产收益率(%)
143 | net_profit_ratio,净利率(%)
144 | gross_profit_rate,毛利率(%)
145 | net_profits,净利润(万元)
146 | eps,每股收益
147 | business_income,营业收入(百万元)
148 | bips,每股主营业务收入(元)
149 | """
150 | self._data = pd.DataFrame()
151 |
152 | if Utility.checkQuarter(year, quarter) is True:
153 | self._writeHead()
154 |
155 | # http://vip.stock.finance.sina.com.cn/q/go.php/vFinanceAnalyze/kind/profit/index.phtml?s_i=&s_a=&s_c=&reportdate=2018&quarter=3&p=1&num=60
156 | self._data = self.__parsePage(cf.PROFIT_URL, year, quarter, 1, cf.PROFIT_COLS, pd.DataFrame(), retry, pause)
157 | if self._data is not None:
158 | self._data['code'] = self._data['code'].map(lambda x: str(x).zfill(6))
159 |
160 | return self._result()
161 |
162 | def operation(self, year, quarter, retry=3, pause=0.001):
163 | """
164 | 获取营运能力数据
165 | Parameters
166 | --------
167 | year:int 年度 e.g:2014
168 | quarter:int 季度 :1、2、3、4,只能输入这4个季度
169 | 说明:由于是从网站获取的数据,需要一页页抓取,速度取决于您当前网络速度
170 | retry : int, 默认 3
171 | 如遇网络等问题重复执行的次数
172 | pause : int, 默认 0.001
173 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
174 | Return
175 | --------
176 | DataFrame or List: [{'code':, 'name':, ...}, ...]
177 | code,代码
178 | name,名称
179 | arturnover,应收账款周转率(次)
180 | arturndays,应收账款周转天数(天)
181 | inventory_turnover,存货周转率(次)
182 | inventory_days,存货周转天数(天)
183 | currentasset_turnover,流动资产周转率(次)
184 | currentasset_days,流动资产周转天数(天)
185 | """
186 | self._data = pd.DataFrame()
187 |
188 | if Utility.checkQuarter(year, quarter) is True:
189 | self._writeHead()
190 |
191 | # http://vip.stock.finance.sina.com.cn/q/go.php/vFinanceAnalyze/kind/operation/index.phtml?s_i=&s_a=&s_c=&reportdate=2018&quarter=3&p=1&num=60
192 | self._data = self.__parsePage(cf.OPERATION_URL, year, quarter, 1, cf.OPERATION_COLS, pd.DataFrame(), retry, pause)
193 | if self._data is not None:
194 | self._data['code'] = self._data['code'].map(lambda x: str(x).zfill(6))
195 |
196 | return self._result()
197 |
198 | def growth(self, year, quarter, retry=3, pause=0.001):
199 | """
200 | 获取成长能力数据
201 | Parameters
202 | --------
203 | year:int 年度 e.g:2014
204 | quarter:int 季度 :1、2、3、4,只能输入这4个季度
205 | 说明:由于是从网站获取的数据,需要一页页抓取,速度取决于您当前网络速度
206 | retry : int, 默认 3
207 | 如遇网络等问题重复执行的次数
208 | pause : int, 默认 0.001
209 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
210 | Return
211 | --------
212 | DataFrame or List: [{'code':, 'name':, ...}, ...]
213 | code,代码
214 | name,名称
215 | mbrg,主营业务收入增长率(%)
216 | nprg,净利润增长率(%)
217 | nav,净资产增长率
218 | targ,总资产增长率
219 | epsg,每股收益增长率
220 | seg,股东权益增长率
221 | """
222 | self._data = pd.DataFrame()
223 |
224 | if Utility.checkQuarter(year, quarter) is True:
225 | self._writeHead()
226 |
227 | # http://vip.stock.finance.sina.com.cn/q/go.php/vFinanceAnalyze/kind/grow/index.phtml?s_i=&s_a=&s_c=&reportdate=2018&quarter=3&p=1&num=60
228 | self._data = self.__parsePage(cf.GROWTH_URL, year, quarter, 1, cf.GROWTH_COLS, pd.DataFrame(), retry, pause)
229 | if self._data is not None:
230 | self._data['code'] = self._data['code'].map(lambda x: str(x).zfill(6))
231 |
232 | return self._result()
233 |
234 | def debtPaying(self, year, quarter, retry=3, pause=0.001):
235 | """
236 | 获取偿债能力数据
237 | Parameters
238 | --------
239 | year:int 年度 e.g:2014
240 | quarter:int 季度 :1、2、3、4,只能输入这4个季度
241 | 说明:由于是从网站获取的数据,需要一页页抓取,速度取决于您当前网络速度
242 | retry : int, 默认 3
243 | 如遇网络等问题重复执行的次数
244 | pause : int, 默认 0.001
245 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
246 | Return
247 | --------
248 | DataFrame or List: [{'code':, 'name':, ...}, ...]
249 | code,代码
250 | name,名称
251 | currentratio,流动比率
252 | quickratio,速动比率
253 | cashratio,现金比率
254 | icratio,利息支付倍数
255 | sheqratio,股东权益比率
256 | adratio,股东权益增长率
257 | """
258 | self._data = pd.DataFrame()
259 |
260 | if Utility.checkQuarter(year, quarter) is True:
261 | self._writeHead()
262 |
263 | # http://vip.stock.finance.sina.com.cn/q/go.php/vFinanceAnalyze/kind/debtpaying/index.phtml?s_i=&s_a=&s_c=&reportdate=2018&quarter=3&p=1&num=60
264 | self._data = self.__parsePage(cf.DEBTPAYING_URL, year, quarter, 1, cf.DEBTPAYING_COLS, pd.DataFrame(), retry, pause)
265 | if self._data is not None:
266 | self._data['code'] = self._data['code'].map(lambda x: str(x).zfill(6))
267 |
268 | return self._result()
269 |
270 | def cashFlow(self, year, quarter, retry=3, pause=0.001):
271 | """
272 | 获取现金流量数据
273 | Parameters
274 | --------
275 | year:int 年度 e.g:2014
276 | quarter:int 季度 :1、2、3、4,只能输入这4个季度
277 | 说明:由于是从网站获取的数据,需要一页页抓取,速度取决于您当前网络速度
278 | retry : int, 默认 3
279 | 如遇网络等问题重复执行的次数
280 | pause : int, 默认 0.001
281 | 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
282 | Return
283 | --------
284 | DataFrame or List: [{'code':, 'name':, ...}, ...]
285 | code,代码
286 | name,名称
287 | cf_sales,经营现金净流量对销售收入比率
288 | rateofreturn,资产的经营现金流量回报率
289 | cf_nm,经营现金净流量与净利润的比率
290 | cf_liabilities,经营现金净流量对负债比率
291 | cashflowratio,现金流量比率
292 | """
293 | self._data = pd.DataFrame()
294 |
295 | if Utility.checkQuarter(year, quarter) is True:
296 | self._writeHead()
297 |
298 | # http://vip.stock.finance.sina.com.cn/q/go.php/vFinanceAnalyze/kind/cashflow/index.phtml?s_i=&s_a=&s_c=&reportdate=2018&quarter=3&p=1&num=60
299 | self._data = self.__parsePage(cf.CASHFLOW_URL, year, quarter, 1, cf.CASHFLOW_COLS, pd.DataFrame(), retry, pause)
300 | if self._data is not None:
301 | self._data['code'] = self._data['code'].map(lambda x: str(x).zfill(6))
302 |
303 | return self._result()
304 |
305 | def __parsePage(self, url, year, quarter, page, column, dataArr, retry, pause, drop_column=None):
306 | self._writeConsole()
307 |
308 | for _ in range(retry):
309 | time.sleep(pause)
310 |
311 | try:
312 | request = self._session.get( url % (year, quarter, page, cf.PAGE_NUM[1]), timeout=10 )
313 | request.encoding = 'gbk'
314 | text = request.text.replace('--', '')
315 | html = lxml.html.parse(StringIO(text))
316 | res = html.xpath("//table[@class=\"list_table\"]/tr")
317 | if self._PY3:
318 | sarr = [etree.tostring(node).decode('utf-8') for node in res]
319 | else:
320 | sarr = [etree.tostring(node) for node in res]
321 | sarr = ''.join(sarr)
322 | sarr = ''%sarr
323 | df = pd.read_html(sarr)[0]
324 | if drop_column is not None:
325 | df = df.drop(drop_column, axis=1)
326 | df.columns = column
327 | dataArr = dataArr.append(df, ignore_index=True)
328 | nextPage = html.xpath('//div[@class=\"pages\"]/a[last()]/@onclick')
329 | if len(nextPage) > 0:
330 | page = re.findall(r'\d+', nextPage[0])[0]
331 | return self.__parsePage(url, year, quarter, page, column, dataArr, retry, pause, drop_column)
332 | else:
333 | return dataArr
334 | except Exception as e:
335 | print(e)
336 |
337 | raise IOError(cf.NETWORK_URL_ERROR_MSG)
338 |
339 |
340 |
--------------------------------------------------------------------------------
/GuGu/utility.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | """
3 | 公用类
4 | Created on 2019/01/15
5 | @author: TabQ
6 | @group : GuGu
7 | @contact: 16621596@qq.com
8 | """
9 |
10 | import datetime
11 | import json
12 | import requests
13 | from requests.adapters import HTTPAdapter
14 | from urllib3.util import Retry
15 | import config as cf
16 |
17 | class Utility():
18 | @staticmethod
19 | def str2Dict(string):
20 | string = eval(string, type('Dummy', (dict,), dict(__getitem__ = lambda s, n:n))())
21 | string = json.dumps(string)
22 |
23 | return json.loads(string)
24 |
25 |
26 | @staticmethod
27 | def checkQuarter(year, quarter):
28 | if isinstance(year, str) or year < 1989 :
29 | raise TypeError(cf.DATE_CHK_MSG)
30 | elif quarter is None or isinstance(quarter, str) or quarter not in [1, 2, 3, 4]:
31 | raise TypeError(cf.DATE_CHK_Q_MSG)
32 | else:
33 | return True
34 |
35 |
36 | @staticmethod
37 | def checkLhbInput(last):
38 | if last not in [5, 10, 30, 60]:
39 | raise TypeError(cf.LHB_MSG)
40 | else:
41 | return True
42 |
43 |
44 | @staticmethod
45 | def symbol(code):
46 | """
47 | 生成symbol代码标志
48 | """
49 | if code in cf.INDEX_LABELS:
50 | return cf.INDEX_LIST[code]
51 | elif len(code) != 6 :
52 | return ''
53 | else:
54 | return 'sh%s' % code if code[:1] in ['5', '6', '9'] else 'sz%s' % code
55 |
56 |
57 | @staticmethod
58 | def random(n=13):
59 | from random import randint
60 |
61 | start = 10**(n-1)
62 | end = (10**n)-1
63 |
64 | return str(randint(start, end))
65 |
66 |
67 | @staticmethod
68 | def getToday():
69 | return str(datetime.datetime.today().date())
70 |
71 |
72 | @staticmethod
73 | def getHour():
74 | return datetime.datetime.today().hour
75 |
76 |
77 | @staticmethod
78 | def getMonth():
79 | return datetime.datetime.today().month
80 |
81 |
82 | @staticmethod
83 | def getYear():
84 | return datetime.datetime.today().year
85 |
86 |
87 | @staticmethod
88 | def getTodayLastYear():
89 | return str(Utility.getTodayHistory(-365))
90 |
91 |
92 | @staticmethod
93 | def getTodayLastMonth():
94 | return str(Utility.getTodayHistory(-30))
95 |
96 |
97 | @staticmethod
98 | def getTodayLastWeek():
99 | return str(Utility.getTodayHistory(-7))
100 |
101 |
102 | @staticmethod
103 | def getTodayHistory(days):
104 | return datetime.datetime.today().date() + datetime.timedelta(days)
105 |
106 |
107 | @staticmethod
108 | def diffDays(start=None, end=None):
109 | d1 = datetime.datetime.strptime(end, '%Y-%m-%d')
110 | d2 = datetime.datetime.strptime(start, '%Y-%m-%d')
111 | delta = d1 - d2
112 |
113 | return delta.days
114 |
115 |
116 | @staticmethod
117 | def ttDates(start='', end=''):
118 | startyear = int(start[0:4])
119 | endyear = int(end[0:4])
120 | dates = [d for d in range(startyear, endyear+1, 2)]
121 |
122 | return dates
123 |
124 |
125 | @staticmethod
126 | def lastTradeDate():
127 | today = datetime.datetime.today().date()
128 | today=int(today.strftime("%w"))
129 |
130 | if today == 0:
131 | return Utility.getTodayHistory(-2)
132 | elif today == 1:
133 | return Utility.getTodayHistory(-3)
134 | else:
135 | return Utility.getTodayHistory(-1)
136 |
137 |
138 | @staticmethod
139 | def isHoliday(date=str(datetime.datetime.today().date())):
140 | """
141 | 节假日判断
142 | Parameters
143 | ------
144 | date: string
145 | 查询日期 format:YYYY-MM-DD 为空时取当前日期
146 | return
147 | ------
148 | True or False
149 | """
150 | session = requests.Session()
151 | retry = Retry(connect=5, backoff_factor=1)
152 | adapter = HTTPAdapter(max_retries=retry)
153 | session.mount('http://', adapter)
154 | session.keep_alive = False
155 |
156 | try:
157 | request = session.get( cf.HOLIDAY_URL % date, timeout=10 )
158 | dataDict = json.loads(request.text)
159 | if dataDict['code'] != 0:
160 | raise IOError(cf.HOLIDAY_SERVE_ERR)
161 | elif dataDict['holiday'] is None:
162 | return False
163 | else:
164 | return True
165 | except Exception as e:
166 | print(e)
167 |
168 |
169 | @staticmethod
170 | def isTradeDay(date=str(datetime.datetime.today().date())):
171 | """
172 | 交易日判断
173 | Parameters
174 | ------
175 | date: string
176 | 查询日期 format:YYYY-MM-DD 为空时取当前日期
177 | return
178 | ------
179 | True or False
180 | """
181 | date = datetime.datetime.strptime(date, '%Y-%m-%d')
182 | w = int(date.strftime('%w'))
183 |
184 | if w in [6, 0]:
185 | return False
186 | else:
187 | return not Utility.isHoliday(date)
188 |
189 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | gugu(股估)
2 |
3 | gugu是适用于量化工程及金融/投资领域数据分析的开源项目,通过对互联网上的公开数据进行采集、清洗和存储,完成了对股票/债券/基金等金融数据的统一调用和分析。其优点是速度快、可定制及高度的可复用性。您不仅可以将其作为单独的数据接口使用,还可以将其集成在您的项目中作为数据获取api进行调用。
4 |
5 | 大家可能之前用过类似的开源项目,本人之前在进行金融数据分析时也是使用其他开源项目获取数据的。然而现在很多开源项目变成了半开源甚至闭源,您需要获取许可才能使用或者需要积累积分才能获得更多的权限,这对于喜欢自己动手并自由定制的朋友会有很多的不便。为了充分发扬开源精神倡导自由软件理念同时为了自身项目需要本人开发了gugu,作为开源社区版的金融数据api,我们承诺gugu将永远开源并不做任何限制以提供给广大金融数据分析及量化爱好者免费使用!
6 |
7 |
8 | Dependencies:
9 |
10 | python 2.x/3.x
11 |
12 | pandas
13 |
14 | Installation
15 |
16 | 方式1: pip install gugu
17 |
18 | 方式2: python setup.py install
19 |
20 | 方式3:访问 https://pypi.python.org/pypi/gugu/ 下载安装
21 |
22 | Upgrade
23 |
24 | pip install gugu --upgrade
25 |
26 | Quick Start
27 | Example 1: 获取大盘指数行情
28 | import gugu as gg
29 |
30 | obj = gg.MarketData() # 创建市场数据类对象
31 | obj.index() # 获取大盘指数行情
32 |
33 | 获取结果:
34 | obj.output() # 打印结果
35 |
36 |
37 | code name change open preclose close high \
38 | 0 sh000001 上证指数 1.30 2597.7777 2584.5724 2618.2323 2618.4765
39 | 1 sh000002 A股指数 1.30 2720.4606 2706.5853 2741.8442 2742.1007
40 | 2 sh000003 B股指数 1.18 271.9034 272.1140 275.3162 275.3162
41 | 3 sh000008 综合指数 0.61 2557.2054 2543.6348 2559.2362 2561.5066
42 | 4 sh000009 上证380 2.47 3892.8231 3880.0032 3975.8523 3976.0933
43 | 5 sh000010 上证180 1.07 7293.4790 7241.9589 7319.4839 7320.2873
44 | 6 sh000011 基金指数 0.90 5642.7602 5629.3801 5679.8086 5679.8339
45 | 7 sh000012 国债指数 0.01 170.9805 170.9642 170.9819 170.9892
46 | 8 sh000016 上证50 0.65 2502.1044 2483.4709 2499.6442 2503.5526
47 | 9 sh000017 新综指 1.30 2193.5148 2182.3286 2210.7524 2210.9592
48 | 10 sh000300 沪深300 1.43 3225.7335 3201.6331 3247.3971 3247.4956
49 | 11 sh000905 中证500 2.82 4189.1098 4176.4739 4294.2696 4295.0379
50 | 12 sz399001 深证成指 2.74 7524.6650 7479.2150 7683.9970 7684.1120
51 | 13 sz399002 深成指R 2.74 9097.7900 9042.8390 9290.4330 9290.5710
52 | 14 sz399003 成份B指 1.99 4442.0740 4445.4680 4534.0600 4534.0600
53 | 15 sz399004 深证100R 2.49 4063.9900 4029.3260 4129.5800 4130.6630
54 | 16 sz399005 中小板指 3.47 4866.8680 4836.6130 5004.4890 5004.4890
55 | 17 sz399006 创业板指 3.53 1233.3840 1227.9880 1271.2750 1272.1930
56 | 18 sz399008 中小300 3.27 947.0020 942.1740 973.0090 973.0090
57 | 19 sz399100 新 指 数 2.69 5850.7930 5819.9190 5976.5880 5976.5880
58 | 20 sz399101 中小板综 3.03 7393.8140 7358.2710 7581.1830 7581.1830
59 | 21 sz399106 深证综指 2.77 1281.1620 1274.7440 1309.9910 1309.9910
60 | 22 sz399107 深证A指 2.77 1339.4990 1332.7690 1369.6510 1369.6510
61 | 23 sz399108 深证B指 2.09 857.4780 856.8890 874.7950 874.7950
62 | 24 sz399333 中小板R 3.47 5412.0040 5378.3600 5565.0400 5565.0400
63 | 25 sz399606 创业板R 3.53 1292.0270 1286.3740 1331.7190 1332.6810
64 |
65 | low volume amount
66 | 0 2590.5543 131986850 1115.2263
67 | 1 2712.8352 131757820 1114.1248
68 | 2 271.9034 229031 1.1015
69 | 3 2538.8951 35179591 275.8689
70 | 4 3892.8231 33132080 260.5541
71 | 5 7247.4721 45958066 529.0995
72 | 6 5637.2069 41987625 243.7168
73 | 7 170.9733 135921 1.3286
74 | 8 2479.3375 21950054 293.6402
75 | 9 2187.3669 130134579 1096.8641
76 | 10 3207.7168 82019641 947.6641
77 | 11 4189.1098 66099677 476.9347
78 | 12 7517.8340 18099026538 1502.2290
79 | 13 9089.5310 8948052337 883.8526
80 | 14 4442.0740 6063605 0.4918
81 | 15 4045.8820 3531953166 453.0613
82 | 16 4866.4270 2440239019 270.5996
83 | 17 1233.3840 1566379186 196.9856
84 | 18 947.0020 4974249025 426.8148
85 | 19 5850.7930 17446832212 1472.6754
86 | 20 7393.8140 8257066751 651.9033
87 | 21 1281.1620 18099026538 1502.2290
88 | 22 1339.4990 18082520936 1501.3883
89 | 23 857.4780 16505602 0.8408
90 | 24 5411.5130 2440239019 270.5996
91 | 25 1292.0270 1566379186 196.9856
92 |
93 | Example 2: 获取指数ETF及其相关数据
94 | obj = gg.MarketData() # 创建市场数据类对象
95 | obj.indexETF() # 获取指数ETF及其相关数据
96 |
97 | 获取结果:
98 | obj.output() # 打印结果
99 |
100 |
101 | fund_id fund_nm index_id creation_unit amount unit_total \
102 | 0 159901 深100ETF 399330 20.0 101937.0 36.95
103 | 1 159902 中 小 板 399005 50.0 74693.0 18.28
104 | 2 159903 深成ETF 399001 300.0 44815.0 3.74
105 | 3 159905 深红利 399324 50.0 52744.0 7.64
106 | 4 159906 深成长 399346 100.0 14364.0 0.95
107 | 5 159907 中小300 399008 150.0 17660.0 1.79
108 | 6 159908 博时创业 399006 150.0 3623.0 0.40
109 | 7 159909 深TMT 399610 25.0 1552.0 0.52
110 | 8 159910 深F120 399702 100.0 48091.0 7.10
111 | 9 159911 民营ETF 399337 50.0 1307.0 0.39
112 | .. ... ... ... ... ... ...
113 | 110 512660 军工ETF 399967 100.0 111508.0 7.25
114 | 111 512680 军工基金 399967 60.0 35932.0 2.29
115 | 112 512700 银行基金 399986 20.0 11058.0 1.11
116 | 113 512800 银行ETF 399986 30.0 57254.0 5.55
117 | 114 512810 军工行业 399967 100.0 8353.0 0.51
118 | 115 512880 证券ETF 399975 100.0 389729.0 30.94
119 | 116 512900 证券基金 399975 30.0 60671.0 4.64
120 | 117 512980 传媒ETF 399971 100.0 110272.0 7.29
121 | 118 513600 恒指ETF NaN 100.0 2883.0 0.72
122 | 119 513660 恒生通 NaN 100.0 33500.0 8.40
123 |
124 | unit_incr price volume increase_rt estimate_value discount_rt \
125 | 0 0.33 3.625 18697.36 2.57 3.6215 0.10
126 | 1 -0.05 2.448 6731.85 3.51 2.4471 0.04
127 | 2 0.00 0.835 77.66 1.83 0.8382 -0.37
128 | 3 0.09 1.448 594.53 1.69 1.4477 0.03
129 | 4 0.00 0.663 9.30 2.31 0.6582 0.30
130 | 5 0.00 1.012 55.09 2.43 1.0128 -0.05
131 | 6 -0.01 1.097 28.92 3.49 1.0976 0.02
132 | 7 0.00 3.375 3.50 1.75 3.4384 -1.79
133 | 8 0.19 1.476 128.26 1.72 1.4767 -0.04
134 | 9 0.00 2.970 4.67 2.73 2.9834 -0.42
135 | .. ... ... ... ... ... ...
136 | 110 0.08 0.650 2920.85 2.20 0.6495 0.08
137 | 111 0.01 0.637 20.94 2.25 0.6388 -0.25
138 | 112 0.00 1.000 69.16 0.10 1.0029 -0.29
139 | 113 -0.10 0.969 2861.82 0.21 0.9688 0.02
140 | 114 0.00 0.614 34.02 2.16 0.6154 -0.18
141 | 115 0.54 0.794 21511.10 2.72 0.7940 0.00
142 | 116 0.00 0.765 391.30 2.82 0.7654 -0.07
143 | 117 0.06 0.661 1043.38 2.64 0.6591 0.20
144 | 118 0.00 2.507 49.85 -0.36 2.5237 -0.81
145 | 119 0.00 2.507 99.09 0.68 2.4765 1.23
146 |
147 | fund_nav nav_dt index_nm index_increase_rt pe pb
148 | 0 3.6212 2019-02-01 深证100 0.0 16.665 2.368
149 | 1 2.4470 2019-02-01 中小板指 0.0 20.140 2.814
150 | 2 0.8381 2019-02-01 深证成指 0.0 17.235 2.121
151 | 3 1.4475 2019-02-01 深证红利 0.0 13.370 2.079
152 | 4 0.6610 2019-02-01 深证成长 0.0 18.516 2.893
153 | 5 1.0125 2019-02-01 中小300 0.0 21.089 2.451
154 | 6 1.0968 2019-02-01 创业板指 0.0 28.853 3.598
155 | 7 3.4364 2019-02-01 TMT50 0.0 27.880 2.940
156 | 8 1.4766 2019-02-01 深证F120 0.0 13.895 1.844
157 | 9 2.9825 2019-02-01 深证民营 0.0 21.518 2.945
158 | .. ... ... ... ... ... ...
159 | 110 0.6495 2019-02-01 中证军工 0.0 47.329 2.166
160 | 111 0.6386 2019-02-01 中证军工 0.0 47.329 2.166
161 | 112 1.0029 2019-02-01 中证银行 0.0 6.588 0.873
162 | 113 0.9688 2019-02-01 中证银行 0.0 6.588 0.873
163 | 114 0.6151 2019-02-01 中证军工 0.0 47.329 2.166
164 | 115 0.7940 2019-02-01 证券公司 0.0 25.216 1.341
165 | 116 0.7655 2019-02-01 证券公司 0.0 25.216 1.341
166 | 117 0.6597 2019-02-01 中证传媒 0.0 19.697 2.362
167 | 118 2.5274 2019-02-01 恒生指数 0.0 NaN NaN
168 | 119 2.4907 2019-01-30 恒生指数 0.0 NaN NaN
169 |
170 | Example 3: 获取股票交易历史数据
171 | obj = gg.StockData('600000') # 创建股票交易类对象
172 | obj.history(start='2019-01-02', end='2019-01-31') # 获取浦发银行2019年1月份的历史数据
173 |
174 | 获取结果:
175 | obj.output() # 打印结果
176 |
177 |
178 | date open close high low volume code
179 | 0 2019-01-02 9.74 9.70 9.79 9.58 237628.0 600000
180 | 1 2019-01-03 9.70 9.81 9.82 9.66 186542.0 600000
181 | 2 2019-01-04 9.73 9.96 10.00 9.70 271728.0 600000
182 | 3 2019-01-07 10.09 9.98 10.09 9.92 235973.0 600000
183 | 4 2019-01-08 10.03 9.96 10.03 9.91 151049.0 600000
184 | 5 2019-01-09 10.06 9.99 10.16 9.98 231637.0 600000
185 | 6 2019-01-10 9.94 9.96 10.02 9.92 159235.0 600000
186 | 7 2019-01-11 10.03 10.05 10.15 9.96 190690.0 600000
187 | 8 2019-01-14 10.03 10.06 10.10 10.01 203528.0 600000
188 | 9 2019-01-15 10.10 10.11 10.15 10.05 156321.0 600000
189 | 10 2019-01-16 10.10 10.13 10.15 10.07 129883.0 600000
190 | 11 2019-01-17 10.17 10.17 10.28 10.07 227660.0 600000
191 | 12 2019-01-18 10.29 10.43 10.44 10.22 290871.0 600000
192 | 13 2019-01-21 10.36 10.35 10.46 10.30 189477.0 600000
193 | 14 2019-01-22 10.38 10.25 10.38 10.23 162505.0 600000
194 | 15 2019-01-23 10.29 10.27 10.34 10.25 165203.0 600000
195 | 16 2019-01-24 10.34 10.38 10.39 10.27 150066.0 600000
196 | 17 2019-01-25 10.45 10.50 10.56 10.38 196965.0 600000
197 | 18 2019-01-28 10.53 10.42 10.66 10.39 217690.0 600000
198 | 19 2019-01-29 10.39 10.58 10.63 10.38 237680.0 600000
199 | 20 2019-01-30 10.59 10.50 10.64 10.47 160542.0 600000
200 | 21 2019-01-31 10.59 10.73 10.73 10.51 251310.0 600000
201 |
202 |
203 | Example 4: 获取三大需求对GDP贡献数据
204 | obj = gg.Macro() # 创建宏观经济数据类对象
205 | obj.demandsToGdp() # 获取获取三大需求对GDP贡献数据
206 |
207 | 获取结果:
208 | obj.output() # 打印结果
209 |
210 |
211 | year cons_to cons_rate asset_to asset_rate goods_to goods_rate
212 | 0 2017 58.8 4.1 32.1 2.2 9.1 0.6
213 | 1 2016 66.5 4.5 43.1 2.9 -9.6 -0.7
214 | 2 2015 59.7 4.1 41.6 2.9 -1.3 -0.1
215 | 3 2014 48.8 3.6 46.9 3.4 4.3 0.3
216 | 4 2013 48.2 3.6 54.2 4.3 -2.3 -0.1
217 | 5 2012 56.7 4.3 42.0 3.4 1.7 0.2
218 | 6 2011 61.9 5.9 46.2 4.4 -8.1 -0.8
219 | 7 2010 46.9 4.8 66.0 7.1 -11.2 -1.3
220 | 8 2009 56.1 5.3 86.5 8.1 -42.6 -4.0
221 | 9 2008 44.2 4.3 53.2 5.1 2.6 0.3
222 | 10 2007 45.3 6.4 44.1 6.3 10.6 1.5
223 | 11 2006 42.0 5.3 42.9 5.5 15.1 1.9
224 | 12 2005 54.4 6.2 33.1 3.8 12.5 1.4
225 | 13 2004 42.6 4.3 61.6 6.2 -4.2 -0.4
226 | 14 2003 35.4 3.6 70.0 7.0 -5.4 -0.6
227 | 15 2002 43.9 5.1 48.5 3.6 4.6 0.4
228 | 16 2001 49.0 4.1 64.0 5.3 -13.0 -1.1
229 | 17 2000 78.1 6.6 22.4 1.9 -0.5 NaN
230 | 18 1999 74.7 5.7 23.7 1.8 1.6 0.1
231 | 19 1998 57.1 4.4 26.4 2.1 16.5 1.3
232 | 20 1997 37.0 3.4 18.6 1.7 44.4 4.2
233 | 21 1996 60.1 6.0 34.3 3.4 5.6 0.6
234 | 22 1995 44.7 4.9 55.0 6.0 0.3 NaN
235 | 23 1994 30.2 4.0 43.8 5.7 26.0 3.4
236 | 24 1993 59.5 8.3 78.6 11.0 -38.1 -5.3
237 | 25 1992 72.5 10.3 34.2 4.9 -6.8 -1.0
238 | 26 1991 65.1 6.0 24.3 2.2 10.6 1.0
239 | 27 1990 47.8 1.8 1.8 0.1 50.4 1.9
240 | 28 1989 39.6 1.6 16.4 0.7 44.0 1.8
241 | 29 1988 49.6 5.6 39.4 4.5 11.0 1.2
242 | 30 1987 50.3 5.8 23.5 2.7 26.2 3.1
243 | 31 1986 45.0 4.0 23.2 2.0 31.8 2.8
244 | 32 1985 85.5 11.5 80.9 10.9 -66.4 -8.9
245 | 33 1984 69.3 10.5 40.5 6.2 -9.8 -1.5
246 | 34 1983 74.1 8.1 40.4 4.4 -14.5 -1.6
247 | 35 1982 64.7 5.9 23.8 2.2 11.5 1.0
248 | 36 1981 93.4 4.9 -4.3 -0.2 10.9 0.5
249 | 37 1980 71.8 5.6 26.4 2.1 1.8 0.1
250 | 38 1979 87.3 6.6 15.4 1.2 -2.7 -0.2
251 | 39 1978 39.4 4.6 66.0 7.7 -5.4 -0.6
252 |
253 | Example 5: 获取可转债及其相关数据
254 | obj = gg.LowRiskIntArb() # 创建低风险及套利类对象
255 | obj.conBonds() # 获取可转债及其相关数据
256 |
257 | 获取结果:
258 | obj.output() # 打印结果
259 |
260 |
261 | bond_id bond_nm stock_id stock_nm market convert_price convert_dt \
262 | 0 127008 特发转债 sz000070 特发信息 sz 6.78 2019-05-22
263 | 1 113506 鼎信转债 sh603421 鼎信通讯 sh 21.65 2018-10-20
264 | 2 113507 天马转债 sh603668 天马科技 sh 7.37 2018-10-23
265 | 3 113520 百合转债 sh603313 梦百合 sh 19.03 2019-05-14
266 | 4 128041 盛路转债 sz002446 盛路通信 sz 6.88 2019-01-23
267 | 5 110032 三一转债 sh600031 三一重工 sh 7.25 2016-07-04
268 | 6 127009 冰轮转债 sz000811 冰轮环境 sz 5.52 2019-07-18
269 | 7 128052 凯龙转债 sz002783 凯龙股份 sz 6.97 2019-06-27
270 | 8 123018 溢利转债 sz300381 溢多利 sz 8.41 2019-06-26
271 | 9 123012 万顺转债 sz300057 万顺股份 sz 6.47 2019-01-26
272 | .. ... ... ... ... ... ... ...
273 | 118 128018 时达转债 sz002527 新时达 sz 11.83 2018-05-10
274 | 119 128028 赣锋转债 sz002460 赣锋锂业 sz 42.58 2018-06-27
275 | 120 128023 亚太转债 sz002284 亚太股份 sz 10.34 2018-06-08
276 | 121 132008 17山高EB sh600350 山东高速 sh 9.62 2018-04-26
277 | 122 127004 模塑转债 sz000700 模塑科技 sz 7.72 2017-12-08
278 | 123 128010 顺昌转债 sz002245 澳洋顺昌 sz 9.28 2016-07-29
279 | 124 123003 蓝思转债 sz300433 蓝思科技 sz 16.08 2018-06-14
280 | 125 132011 17浙报EB sh600633 浙数文化 sh 24.39 2018-08-17
281 | 126 128012 辉丰转债 sz002496 ST辉丰 sz 7.71 2016-10-28
282 | 127 128013 洪涛转债 sz002325 洪涛股份 sz 9.98 2017-02-06
283 |
284 | Example 6: 股票LOF基金及基相关数据
285 | obj = gg.LowRiskIntArb() # 创建低风险及套利类对象
286 | obj.stockLof() # 获取股票LOF基金及基相关数据
287 |
288 | 获取结果:
289 | obj.output() # 打印结果
290 |
291 |
292 | fund_id fund_nm price increase_rt volume amount fund_nav nav_dt \
293 | 0 160105 南方积配 0.812 1.37 6.73 2175.0 0.8155 2019-02-01
294 | 1 160106 南方高增 0.847 2.05 13.22 6851.0 0.8666 2019-02-01
295 | 2 160133 南方天元 1.956 0.98 28.82 22162.0 1.9830 2019-02-01
296 | 3 160211 国泰小盘 1.647 1.92 41.34 5115.0 1.6620 2019-02-01
297 | 4 160212 国泰估值 1.658 2.35 64.51 8375.0 1.6750 2019-02-01
298 | 5 160215 国泰价值 1.192 1.27 10.85 2205.0 1.1990 2019-02-01
299 | 6 160220 国泰民益 1.132 1.71 3.83 3223.0 1.1382 2019-02-01
300 | 7 160311 华夏蓝筹 1.297 0.93 27.65 10515.0 1.3040 2019-02-01
301 | 8 160314 华夏行业 0.842 1.45 12.76 13094.0 0.8490 2019-02-01
302 | 9 160323 华夏磐泰 1.009 0.00 0.00 145.0 0.9721 2019-02-01
303 | .. ... ... ... ... ... ... ... ...
304 | 68 168401 红土定增 0.966 0.00 1.04 1010.0 1.0139 2019-02-01
305 | 69 169101 东证睿丰 1.252 1.54 356.30 39830.0 1.2600 2019-02-01
306 | 70 169201 浙商鼎盈 0.971 0.00 0.00 771.0 0.9783 2019-02-01
307 | 71 501000 国金鑫新 0.961 4.34 2.09 82.0 0.9460 2019-02-01
308 | 72 501001 财通精选 0.953 -2.46 10.37 5423.0 0.9590 2019-02-01
309 | 73 501015 财通升级 0.757 0.40 12.29 36579.0 0.7650 2019-02-01
310 | 74 501017 国泰融丰 0.783 0.00 0.00 5178.0 0.7768 2019-02-01
311 | 75 501022 银华鑫盛 0.779 0.39 3.33 12266.0 0.7980 2019-02-01
312 | 76 501027 国泰融信 0.989 0.00 0.00 311.0 1.0055 2019-02-01
313 | 77 501035 创金睿选 0.938 0.32 2.14 877.0 0.9627 2019-02-01
314 |
315 | 更多文档:
316 |
317 | 请查阅文档
318 |
319 | Change Log:
320 | 0.1.0 2019/02/03
321 | 创建第一个版本
322 |
323 |
324 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [egg_info]
2 | tag_build =
3 | tag_date = 0
4 | tag_svn_revision = 0
5 |
6 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | from setuptools import setup, find_packages
4 |
5 | try:
6 | import pypandoc
7 | long_description = pypandoc.convert('README.md', 'rst')
8 | except (IOError, ImportError):
9 | long_description = ''
10 |
11 |
12 | setup(
13 | name='GuGu',
14 | version='0.1.0',
15 | description='an api for getting financial data',
16 | long_description=long_description,
17 | author='TabQ',
18 | author_email='16621596@qq.com',
19 | url='http://www.infodata.cc',
20 | license="Apache License, Version 2.0",
21 | packages=find_packages(),
22 | install_requires=[
23 | 'pandas',
24 | 'requests',
25 | 'lxml',
26 | 'simplejson',
27 | 'xlrd'
28 | ],
29 | keywords='Financial Data Crawler',
30 | classifiers=['Development Status :: 4 - Beta',
31 | 'Programming Language :: Python :: 2.6',
32 | 'Programming Language :: Python :: 2.7',
33 | 'Programming Language :: Python :: 3.2',
34 | 'Programming Language :: Python :: 3.3',
35 | 'Programming Language :: Python :: 3.4',
36 | 'Programming Language :: Python :: 3.5'],
37 | )
38 |
--------------------------------------------------------------------------------