tushare 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +59 -0
- data/LICENSE.txt +28 -0
- data/README.md +41 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/lib/tushare.rb +18 -0
- data/lib/tushare/datayes.rb +50 -0
- data/lib/tushare/datayes/bond.rb +69 -0
- data/lib/tushare/datayes/constants.rb +598 -0
- data/lib/tushare/datayes/equity.rb +111 -0
- data/lib/tushare/datayes/fund.rb +115 -0
- data/lib/tushare/datayes/fundamental.rb +260 -0
- data/lib/tushare/datayes/future.rb +22 -0
- data/lib/tushare/datayes/hk_equity.rb +18 -0
- data/lib/tushare/datayes/idx.rb +19 -0
- data/lib/tushare/datayes/iv.rb +60 -0
- data/lib/tushare/datayes/macro.rb +3517 -0
- data/lib/tushare/datayes/market.rb +286 -0
- data/lib/tushare/datayes/master.rb +67 -0
- data/lib/tushare/datayes/options.rb +22 -0
- data/lib/tushare/datayes/subject.rb +349 -0
- data/lib/tushare/internet/box_office.rb +155 -0
- data/lib/tushare/stock/billboard.rb +197 -0
- data/lib/tushare/stock/classifying.rb +288 -0
- data/lib/tushare/stock/fundamental.rb +232 -0
- data/lib/tushare/stock/macro.rb +253 -0
- data/lib/tushare/stock/news_event.rb +165 -0
- data/lib/tushare/stock/reference.rb +473 -0
- data/lib/tushare/stock/shibor.rb +136 -0
- data/lib/tushare/stock/trading.rb +513 -0
- data/lib/tushare/util.rb +293 -0
- data/lib/tushare/version.rb +3 -0
- data/tushare.gemspec +32 -0
- metadata +211 -0
@@ -0,0 +1,165 @@
|
|
1
|
+
require 'tushare/util'
|
2
|
+
|
3
|
+
module Tushare
|
4
|
+
module Stock
|
5
|
+
# 新闻事件数据接口
|
6
|
+
module NewsEvent
|
7
|
+
extend Tushare::Util
|
8
|
+
|
9
|
+
# 获取即时财经新闻
|
10
|
+
|
11
|
+
# Parameters
|
12
|
+
# --------
|
13
|
+
# top:数值,显示最新消息的条数,默认为80条
|
14
|
+
# show_content:是否显示新闻内容,默认False
|
15
|
+
|
16
|
+
# Return
|
17
|
+
# --------
|
18
|
+
# DataFrame
|
19
|
+
# classify :新闻类别
|
20
|
+
# title :新闻标题
|
21
|
+
# time :发布时间
|
22
|
+
# url :新闻链接
|
23
|
+
# content:新闻内容(在show_content为True的情况下出现)
|
24
|
+
def latest_news(top = PAGE_NUM[2], show_content = false)
|
25
|
+
url = format(LATEST_URL, P_TYPE['http'], DOMAINS['sina'],
|
26
|
+
PAGES['lnews'], top, _random)
|
27
|
+
resp = HTTParty.get(url)
|
28
|
+
events = eval(resp.body.encode('utf-8', 'gbk').sub('var ', '')
|
29
|
+
.delete(' '))[:list]
|
30
|
+
result = []
|
31
|
+
events.each do |event|
|
32
|
+
object = {}
|
33
|
+
object['classify'] = event[:channel][:title]
|
34
|
+
object['title'] = event[:title]
|
35
|
+
object['url'] = event[:url]
|
36
|
+
object['time'] = Time.at(event[:time]).strftime('%m-%d %H:%M')
|
37
|
+
object['content'] = latest_content(object['url']) if show_content
|
38
|
+
result << object
|
39
|
+
end
|
40
|
+
result
|
41
|
+
end
|
42
|
+
|
43
|
+
# 个股信息地雷
|
44
|
+
# Parameters
|
45
|
+
# --------
|
46
|
+
# code:股票代码
|
47
|
+
# date:信息公布日期
|
48
|
+
|
49
|
+
# Return
|
50
|
+
# --------
|
51
|
+
# DataFrame,属性列表:
|
52
|
+
# title:信息标题
|
53
|
+
# type:信息类型
|
54
|
+
# date:公告日期
|
55
|
+
# url:信息内容URL
|
56
|
+
def notices(code, date = nil)
|
57
|
+
return nil if code.nil?
|
58
|
+
symbol = code[0] == '6' ? "sh#{code}" : "sz#{code}"
|
59
|
+
url = format(NOTICE_INFO_URL, P_TYPE['http'], DOMAINS['vsf'],
|
60
|
+
PAGES['ntinfo'], symbol)
|
61
|
+
url = "#{url}&gg_date=#{date}" if date
|
62
|
+
doc = Nokogiri::HTML(open(url), nil, 'gbk')
|
63
|
+
rows = doc.css('table.body_table tbody tr')
|
64
|
+
result = []
|
65
|
+
rows.each do |row|
|
66
|
+
object = {}
|
67
|
+
a = row.css('th a')[0]
|
68
|
+
tds = row.css('td')
|
69
|
+
object['title'] = a.content
|
70
|
+
object['type'] = tds[0].content
|
71
|
+
object['date'] = tds[1].content
|
72
|
+
object['url'] = "#{P_TYPE['http']}#{DOMAINS['vsf']}#{a.attr('href')}"
|
73
|
+
result << object
|
74
|
+
end
|
75
|
+
result
|
76
|
+
end
|
77
|
+
|
78
|
+
# 获取信息地雷内容
|
79
|
+
# Parameter
|
80
|
+
# --------
|
81
|
+
# url:内容链接
|
82
|
+
|
83
|
+
# Return
|
84
|
+
# --------
|
85
|
+
# string:信息内容
|
86
|
+
def notice_content(url)
|
87
|
+
doc = Nokogiri::HTML(open(url))
|
88
|
+
doc.css('div#content pre')[0].content.strip
|
89
|
+
end
|
90
|
+
|
91
|
+
# 获取sina财经股吧首页的重点消息
|
92
|
+
# Parameter
|
93
|
+
# --------
|
94
|
+
# show_content:是否显示内容,默认False
|
95
|
+
|
96
|
+
# Return
|
97
|
+
# --------
|
98
|
+
# DataFrame
|
99
|
+
# title, 消息标题
|
100
|
+
# content, 消息内容(show_content=True的情况下)
|
101
|
+
# ptime, 发布时间
|
102
|
+
# rcounts,阅读次数
|
103
|
+
def guba_sina(show_content = false)
|
104
|
+
url = format(GUBA_SINA_URL, P_TYPE['http'], DOMAINS['sina'])
|
105
|
+
doc = Nokogiri::HTML(open(url), nil, 'gbk')
|
106
|
+
res = doc.css('ul.list_05 li')
|
107
|
+
heads = doc.css('div.tit_04')
|
108
|
+
result = []
|
109
|
+
heads.each do |head|
|
110
|
+
object = {}
|
111
|
+
link = head.css('a').first
|
112
|
+
object[:title] = link.content
|
113
|
+
object[:url] = link.attr('href')
|
114
|
+
object.merge!(_guba_content(object[:url]))
|
115
|
+
object.delete(:content) unless show_content
|
116
|
+
result << object
|
117
|
+
end
|
118
|
+
res.each do |row|
|
119
|
+
object = {}
|
120
|
+
link = row.css('a')[1]
|
121
|
+
object[:title] = link.text
|
122
|
+
object[:url] = link.attr('href')
|
123
|
+
object.merge!(_guba_content(object[:url]))
|
124
|
+
object.delete(:content) unless show_content
|
125
|
+
result << object
|
126
|
+
end
|
127
|
+
|
128
|
+
result
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
def _guba_content(url)
|
134
|
+
doc = Nokogiri::HTML(open(url), nil, 'gbk')
|
135
|
+
content = doc.css('div.ilt_p p').text
|
136
|
+
ptime = doc.css('div.fl_left.iltp_time span').text
|
137
|
+
rcounts_text = doc.css('div.fl_right.iltp_span span')[1].text
|
138
|
+
rcounts = rcounts_text.gsub(/\D/, '')
|
139
|
+
{ content: content, ptime: ptime, rcounts: rcounts }
|
140
|
+
end
|
141
|
+
|
142
|
+
# 获取即时财经新闻内容
|
143
|
+
# Parameter
|
144
|
+
# --------
|
145
|
+
# url:新闻链接
|
146
|
+
|
147
|
+
# Return
|
148
|
+
# --------
|
149
|
+
# string:返回新闻的文字内容
|
150
|
+
def latest_content(url)
|
151
|
+
doc = Nokogiri::HTML(open(url))
|
152
|
+
doc.css('div#artibody p').text
|
153
|
+
end
|
154
|
+
|
155
|
+
def _random(n = 16)
|
156
|
+
start_point = 10 ** (n - 1)
|
157
|
+
end_point = (10 ** n) - 1
|
158
|
+
rand(start_point..end_point).to_s
|
159
|
+
end
|
160
|
+
|
161
|
+
module_function :latest_news, :notices, :guba_sina, :_guba_content,
|
162
|
+
:latest_content, :_random
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
@@ -0,0 +1,473 @@
|
|
1
|
+
require 'tushare/util'
|
2
|
+
|
3
|
+
module Tushare
|
4
|
+
module Stock
|
5
|
+
# 投资参考数据接口
|
6
|
+
module Reference
|
7
|
+
extend Tushare::Util
|
8
|
+
|
9
|
+
# 获取分配预案数据
|
10
|
+
# Parameters
|
11
|
+
# year:年份
|
12
|
+
# start_page: 开始页数
|
13
|
+
|
14
|
+
# returns
|
15
|
+
# code:股票代码
|
16
|
+
# name:股票名称
|
17
|
+
# year:分配年份
|
18
|
+
# report_date:公布日期
|
19
|
+
# divi:分红金额(每10股)
|
20
|
+
# shares:转增和送股数(每10股)
|
21
|
+
def profit_data(year = Time.now.year, start_page = 0)
|
22
|
+
doc_generator = lambda do |p|
|
23
|
+
url = format(DP_163_URL, P_TYPE['http'], DOMAINS['163'],
|
24
|
+
PAGES['163dp'], year, p)
|
25
|
+
Nokogiri.HTML(open(url))
|
26
|
+
end
|
27
|
+
row_finder = lambda do |doc|
|
28
|
+
doc.css('div.fn_rp_list table > tr')
|
29
|
+
end
|
30
|
+
row_processor = lambda do |row|
|
31
|
+
row.drop(1).map { |item| item.content.strip }
|
32
|
+
end
|
33
|
+
last_page_guard = lambda do |doc|
|
34
|
+
last_element = doc.css('div.mod_pages > :last-child').first
|
35
|
+
last_element.name == 'span'
|
36
|
+
end
|
37
|
+
get_data(0, DP_163_COLS, doc_generator, row_finder,
|
38
|
+
row_processor, last_page_guard)
|
39
|
+
end
|
40
|
+
|
41
|
+
# 获取业绩预告数据
|
42
|
+
# Parameters
|
43
|
+
# --------
|
44
|
+
# year:int 年度 e.g:2014
|
45
|
+
# quarter:int 季度 :1、2、3、4,只能输入这4个季度
|
46
|
+
# 说明:由于是从网站获取的数据,需要一页页抓取,速度取决于您当前网络速度
|
47
|
+
|
48
|
+
# Return
|
49
|
+
# --------
|
50
|
+
# DataFrame
|
51
|
+
# code,代码
|
52
|
+
# name,名称
|
53
|
+
# type,业绩变动类型【预增、预亏等】
|
54
|
+
# report_date,发布日期
|
55
|
+
# pre_eps,上年同期每股收益
|
56
|
+
# range,业绩变动范围
|
57
|
+
def forecast_data(year, quarter)
|
58
|
+
check_year(year)
|
59
|
+
check_quarter(quarter)
|
60
|
+
doc_generator = lambda do |p|
|
61
|
+
url = format(FORECAST_URL, P_TYPE['http'], DOMAINS['vsf'],
|
62
|
+
PAGES['fd'], year, quarter, p, PAGE_NUM[1])
|
63
|
+
Nokogiri.HTML(open(url), nil, 'gbk')
|
64
|
+
end
|
65
|
+
row_finder = lambda do |doc|
|
66
|
+
doc.css('table.list_table > tr')
|
67
|
+
end
|
68
|
+
row_processor = lambda do |row|
|
69
|
+
row.to_a.values_at(0, 1, 2, 3, 6, 7).map { |item| item.content.strip }
|
70
|
+
end
|
71
|
+
last_page_guard = lambda do |doc|
|
72
|
+
next_page = doc.css('div.pages > a:last').css('a.nolink')
|
73
|
+
!next_page.empty?
|
74
|
+
end
|
75
|
+
get_data(1, FORECAST_COLS, doc_generator, row_finder,
|
76
|
+
row_processor, last_page_guard)
|
77
|
+
end
|
78
|
+
|
79
|
+
# 获取限售股解禁数据
|
80
|
+
# Parameters
|
81
|
+
# --------
|
82
|
+
# year:年份,默认为当前年
|
83
|
+
# month:解禁月份,默认为当前月
|
84
|
+
# retry_count : int, 默认 3
|
85
|
+
# 如遇网络等问题重复执行的次数
|
86
|
+
# pause : int, 默认 0
|
87
|
+
# 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
|
88
|
+
|
89
|
+
# Return
|
90
|
+
# ------
|
91
|
+
# DataFrame
|
92
|
+
# code:股票代码
|
93
|
+
# name:名称
|
94
|
+
# date:解禁日期
|
95
|
+
# count:解禁数量(万股)
|
96
|
+
# ratio:占总盘比率
|
97
|
+
def xsg_data(year = Time.now.year, month = Time.now.month)
|
98
|
+
url = format(XSG_URL, P_TYPE['http'], DOMAINS['em'], PAGES['emxsg'], year,
|
99
|
+
month)
|
100
|
+
lines = HTTParty.get(url).slice(3..-3)
|
101
|
+
lines.split('","').map do |row|
|
102
|
+
arr = row.split(',').values_at(1, 3, 4, 5, 6)
|
103
|
+
arr[3] = (arr[3].to_f / 10_000).round(2)
|
104
|
+
arr[4] = (arr[4].to_f * 100).round(2)
|
105
|
+
object = {}
|
106
|
+
XSG_COLS.each_with_index do |key, index|
|
107
|
+
object[key] = arr[index]
|
108
|
+
end
|
109
|
+
object
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# 获取基金持股数据
|
114
|
+
# Parameters
|
115
|
+
# --------
|
116
|
+
# year:年份e.g 2014
|
117
|
+
# quarter:季度(只能输入1,2,3,4这个四个数字)
|
118
|
+
|
119
|
+
# Return
|
120
|
+
# ------
|
121
|
+
# DataFrame
|
122
|
+
# code:股票代码
|
123
|
+
# name:名称
|
124
|
+
# date:报告日期
|
125
|
+
# nums:基金家数
|
126
|
+
# nlast:与上期相比(增加或减少了)
|
127
|
+
# count:基金持股数(万股)
|
128
|
+
# clast:与上期相比
|
129
|
+
# amount:基金持股市值
|
130
|
+
# ratio:占流通盘比率
|
131
|
+
def fund_holdings(year, quarter)
|
132
|
+
check_year(year)
|
133
|
+
check_quarter(quarter)
|
134
|
+
start_date, end_date = QUARTS_DIC[quarter.to_s]
|
135
|
+
start_date = format(start_date % (quarter == 1 && year - 1 || year))
|
136
|
+
end_date = format(end_date % year)
|
137
|
+
url_generator = lambda do |page|
|
138
|
+
format(FUND_HOLDS_URL, P_TYPE['http'], DOMAINS['163'], PAGES['163fh'],
|
139
|
+
PAGES['163fh'], page, start_date, end_date, rand(5))
|
140
|
+
end
|
141
|
+
resp = HTTParty.get(url_generator.call(0))
|
142
|
+
page_count = JSON.parse(resp)['pagecount']
|
143
|
+
result = []
|
144
|
+
1.upto(page_count) do |page|
|
145
|
+
_write_console
|
146
|
+
resp = HTTParty.get url_generator.call(page)
|
147
|
+
data = JSON.parse(resp)['list']
|
148
|
+
data.each do |datum|
|
149
|
+
object = {}
|
150
|
+
object['code'] = datum['SYMBOL']
|
151
|
+
object['name'] = datum['SNAME']
|
152
|
+
object['date'] = datum['REPORTDATE']
|
153
|
+
object['nums'] = datum['SHULIANG']
|
154
|
+
object['nlast'] = datum['SHULIANGBIJIAO']
|
155
|
+
object['count'] = (datum['GUSHU'].to_f / 10_000).round(2)
|
156
|
+
object['clast'] = (datum['GUSHUBIJIAO'].to_f / 10_000).round(2)
|
157
|
+
object['amount'] = (datum['SHIZHI'].to_f / 10_000).round(2)
|
158
|
+
object['ratio'] = (datum['SCSTC27'].to_f * 100).round(2)
|
159
|
+
result << object
|
160
|
+
end
|
161
|
+
end
|
162
|
+
result
|
163
|
+
end
|
164
|
+
|
165
|
+
# 获取新股上市数据
|
166
|
+
# Parameters
|
167
|
+
# --------
|
168
|
+
# retry_count : int, 默认 3
|
169
|
+
# 如遇网络等问题重复执行的次数
|
170
|
+
# pause : int, 默认 0
|
171
|
+
# 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
|
172
|
+
|
173
|
+
# Return
|
174
|
+
# ------
|
175
|
+
# DataFrame
|
176
|
+
# code:股票代码
|
177
|
+
# name:名称
|
178
|
+
# ipo_date:上网发行日期
|
179
|
+
# issue_date:上市日期
|
180
|
+
# amount:发行数量(万股)
|
181
|
+
# markets:上网发行数量(万股)
|
182
|
+
# price:发行价格(元)
|
183
|
+
# pe:发行市盈率
|
184
|
+
# limit:个人申购上限(万股)
|
185
|
+
# funds:募集资金(亿元)
|
186
|
+
# ballot:网上中签率(%)
|
187
|
+
def new_stocks
|
188
|
+
url = format(NEW_STOCKS_URL, P_TYPE['http'], DOMAINS['vsf'],
|
189
|
+
PAGES['newstock'], 1)
|
190
|
+
doc_generator = lambda do |p|
|
191
|
+
url = format(NEW_STOCKS_URL, P_TYPE['http'], DOMAINS['vsf'],
|
192
|
+
PAGES['newstock'], p)
|
193
|
+
Nokogiri.HTML open(url), nil, 'gbk'
|
194
|
+
end
|
195
|
+
row_finder = lambda do |doc|
|
196
|
+
doc.css('table#NewStockTable > tr').drop(2)
|
197
|
+
end
|
198
|
+
row_processor = lambda do |row|
|
199
|
+
arr = row.to_a
|
200
|
+
arr.delete_at 1
|
201
|
+
arr.map(&:content).map(&:strip)
|
202
|
+
end
|
203
|
+
last_page_guard = lambda do |doc|
|
204
|
+
doc.css('table.table2 tr:first td:first a').last.text != '尾页'
|
205
|
+
end
|
206
|
+
get_data(1, NEW_STOCKS_COLS, doc_generator, row_finder,
|
207
|
+
row_processor, last_page_guard)
|
208
|
+
end
|
209
|
+
|
210
|
+
# 获取沪市融资融券数据列表
|
211
|
+
# Parameters
|
212
|
+
# --------
|
213
|
+
# start:string
|
214
|
+
# 开始日期 format:YYYY-MM-DD 为空时取去年今日
|
215
|
+
# end:string
|
216
|
+
# 结束日期 format:YYYY-MM-DD 为空时取当前日期
|
217
|
+
# retry_count : int, 默认 3
|
218
|
+
# 如遇网络等问题重复执行的次数
|
219
|
+
# pause : int, 默认 0
|
220
|
+
# 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
|
221
|
+
|
222
|
+
# Return
|
223
|
+
# ------
|
224
|
+
# DataFrame
|
225
|
+
# opDate:信用交易日期
|
226
|
+
# rzye:本日融资余额(元)
|
227
|
+
# rzmre: 本日融资买入额(元)
|
228
|
+
# rqyl: 本日融券余量
|
229
|
+
# rqylje: 本日融券余量金额(元)
|
230
|
+
# rqmcl: 本日融券卖出量
|
231
|
+
# rzrqjyzl:本日融资融券余额(元)
|
232
|
+
def sh_margins(start_date = nil, end_date = nil)
|
233
|
+
start_date ||= Date.today.prev_year.strftime('%Y-%m-%d')
|
234
|
+
end_date ||= Date.today.strftime('%Y-%m-%d')
|
235
|
+
start_date = start_date.delete '-'
|
236
|
+
end_date = end_date.delete '-'
|
237
|
+
page_no = ''
|
238
|
+
begin_page = ''
|
239
|
+
end_page = ''
|
240
|
+
result = []
|
241
|
+
|
242
|
+
loop do
|
243
|
+
tail = format(MAR_SH_HZ_TAIL_URL, page_no, begin_page, end_page)
|
244
|
+
if page_no == ''
|
245
|
+
page_no = 6
|
246
|
+
tail = ''
|
247
|
+
else
|
248
|
+
page_no += 5
|
249
|
+
end
|
250
|
+
begin_page = page_no
|
251
|
+
end_page = page_no + 4
|
252
|
+
url = format(MAR_SH_HZ_URL, P_TYPE['http'], DOMAINS['sseq'],
|
253
|
+
PAGES['qmd'], _random(5), start_date, end_date, tail,
|
254
|
+
_random)
|
255
|
+
ref = format(MAR_SH_HZ_REF_URL, P_TYPE['http'], DOMAINS['sse'])
|
256
|
+
resp = HTTParty.get(
|
257
|
+
url,
|
258
|
+
headers: { 'Referer' => ref },
|
259
|
+
cookies: MAR_SH_COOKIES
|
260
|
+
)
|
261
|
+
json = JSON.parse(resp.body.sub(/jsonpCallback\d+\(/, '')[0..-2])['pageHelp']
|
262
|
+
|
263
|
+
json['data'].each do |datum|
|
264
|
+
object = {}
|
265
|
+
MAR_SH_HZ_COLS.each do |key|
|
266
|
+
if key == 'opDate'
|
267
|
+
date = datum[key]
|
268
|
+
object[key] = format('%s-%s-%s', date[0..3], date[4..5], date[6..7])
|
269
|
+
else
|
270
|
+
object[key] = datum[key]
|
271
|
+
end
|
272
|
+
end
|
273
|
+
result << object
|
274
|
+
end
|
275
|
+
|
276
|
+
page_count = json['pageCount']
|
277
|
+
data_page = page_count % 5 > 0 ? page_count / 5 + 1 : page_count / 5
|
278
|
+
break unless begin_page < data_page * 5
|
279
|
+
end
|
280
|
+
result
|
281
|
+
end
|
282
|
+
|
283
|
+
# 获取沪市融资融券明细列表
|
284
|
+
# Parameters
|
285
|
+
# --------
|
286
|
+
# date:string
|
287
|
+
# 明细数据日期 format:YYYY-MM-DD 默认为空''
|
288
|
+
# symbol:string
|
289
|
+
# 标的代码,6位数字e.g.600848,默认为空
|
290
|
+
# start:string
|
291
|
+
# 开始日期 format:YYYY-MM-DD 默认为空''
|
292
|
+
# end:string
|
293
|
+
# 结束日期 format:YYYY-MM-DD 默认为空''
|
294
|
+
# retry_count : int, 默认 3
|
295
|
+
# 如遇网络等问题重复执行的次数
|
296
|
+
# pause : int, 默认 0
|
297
|
+
# 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
|
298
|
+
|
299
|
+
# Return
|
300
|
+
# ------
|
301
|
+
# DataFrame
|
302
|
+
# opDate:信用交易日期
|
303
|
+
# stockCode:标的证券代码
|
304
|
+
# securityAbbr:标的证券简称
|
305
|
+
# rzye:本日融资余额(元)
|
306
|
+
# rzmre: 本日融资买入额(元)
|
307
|
+
# rzche:本日融资偿还额(元)
|
308
|
+
# rqyl: 本日融券余量
|
309
|
+
# rqmcl: 本日融券卖出量
|
310
|
+
# rqchl: 本日融券偿还量
|
311
|
+
def sh_margin_details(date = '', symbol = '', start_date = '', end_date = '')
|
312
|
+
date = date == '' ? date : date.delete('-')
|
313
|
+
start_date = start_date == '' ? start_date : start_date.delete('-')
|
314
|
+
end_date = end_date == '' ? end_date : end_date.delete('-')
|
315
|
+
date = '' if start_date != '' && end_date != ''
|
316
|
+
page_no = ''
|
317
|
+
begin_page = ''
|
318
|
+
end_page = ''
|
319
|
+
result = []
|
320
|
+
|
321
|
+
loop do
|
322
|
+
tail = format(MAR_SH_HZ_TAIL_URL, page_no, begin_page, end_page)
|
323
|
+
if page_no == ''
|
324
|
+
page_no = 6
|
325
|
+
tail = ''
|
326
|
+
else
|
327
|
+
page_no += 5
|
328
|
+
end
|
329
|
+
begin_page = page_no
|
330
|
+
end_page = page_no + 4
|
331
|
+
url = format(MAR_SH_MX_URL, P_TYPE['http'], DOMAINS['sseq'],
|
332
|
+
PAGES['qmd'], _random(5), date, symbol, start_date,
|
333
|
+
end_date, tail, _random)
|
334
|
+
ref = format(MAR_SH_HZ_REF_URL, P_TYPE['http'], DOMAINS['sse'])
|
335
|
+
resp = HTTParty.get(
|
336
|
+
url,
|
337
|
+
headers: { 'Referer' => ref },
|
338
|
+
cookies: MAR_SH_COOKIES
|
339
|
+
)
|
340
|
+
json = JSON.parse(resp.body.sub(/jsonpCallback\d+\(/, '')[0..-2])['pageHelp']
|
341
|
+
|
342
|
+
json['data'].each do |datum|
|
343
|
+
object = {}
|
344
|
+
MAR_SH_MX_COLS.each do |key|
|
345
|
+
if key == 'opDate'
|
346
|
+
date = datum[key]
|
347
|
+
object[key] = format('%s-%s-%s', date[0..3], date[4..5], date[6..7])
|
348
|
+
else
|
349
|
+
object[key] = datum[key]
|
350
|
+
end
|
351
|
+
end
|
352
|
+
result << object
|
353
|
+
end
|
354
|
+
|
355
|
+
page_count = json['pageCount']
|
356
|
+
data_page = page_count % 5 > 0 ? page_count / 5 + 1 : page_count / 5
|
357
|
+
p result.size
|
358
|
+
break unless begin_page < data_page * 5
|
359
|
+
end
|
360
|
+
result
|
361
|
+
end
|
362
|
+
|
363
|
+
def sz_margins(start_date = nil, end_date = nil)
|
364
|
+
if start_date.nil? && end_date.nil?
|
365
|
+
start_date ||= Date.today.prev_day(7)
|
366
|
+
end_date ||= Date.today
|
367
|
+
end
|
368
|
+
raise MAR_SZ_HZ_MSG2 if start_date.nil? || end_date.nil?
|
369
|
+
range = (start_date..end_date).to_a
|
370
|
+
raise MAR_SZ_HZ_MSG if range.size > 261
|
371
|
+
_write_head
|
372
|
+
result = []
|
373
|
+
range.each do |date|
|
374
|
+
_write_console
|
375
|
+
url = format(MAR_SZ_HZ_URL, P_TYPE['http'], DOMAINS['szse'],
|
376
|
+
PAGES['szsefc'], date.strftime('%Y-%m-%d'))
|
377
|
+
doc = Nokogiri::HTML(open(url), nil, 'gbk')
|
378
|
+
begin
|
379
|
+
row = doc.css('tr')[1].css('td')
|
380
|
+
rescue
|
381
|
+
next
|
382
|
+
end
|
383
|
+
object = { 'opDate' => date}
|
384
|
+
MAR_SZ_HZ_COLS.each_with_index do |key, index|
|
385
|
+
object[key] = row[index].content.strip
|
386
|
+
end
|
387
|
+
result << object
|
388
|
+
end
|
389
|
+
puts "\n"
|
390
|
+
result
|
391
|
+
end
|
392
|
+
|
393
|
+
# 获取深市融资融券明细列表
|
394
|
+
# Parameters
|
395
|
+
# --------
|
396
|
+
# date:string
|
397
|
+
# 明细数据日期 format:YYYY-MM-DD 默认为空''
|
398
|
+
# retry_count : int, 默认 3
|
399
|
+
# 如遇网络等问题重复执行的次数
|
400
|
+
# pause : int, 默认 0
|
401
|
+
# 重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
|
402
|
+
|
403
|
+
# Return
|
404
|
+
# ------
|
405
|
+
# DataFrame
|
406
|
+
# opDate:信用交易日期
|
407
|
+
# stockCode:标的证券代码
|
408
|
+
# securityAbbr:标的证券简称
|
409
|
+
# rzmre: 融资买入额(元)
|
410
|
+
# rzye:融资余额(元)
|
411
|
+
# rqmcl: 融券卖出量
|
412
|
+
# rqyl: 融券余量
|
413
|
+
# rqye: 融券余量(元)
|
414
|
+
# rzrqye:融资融券余额(元)
|
415
|
+
def sz_margin_details(date = nil)
|
416
|
+
date ||= Date.today.prev_day.strftime('%Y-%m-%d')
|
417
|
+
url = format(MAR_SZ_MX_URL, P_TYPE['http'], DOMAINS['szse'],
|
418
|
+
PAGES['szsefc'], date)
|
419
|
+
doc = Nokogiri::HTML(open(url), nil, 'gbk')
|
420
|
+
rows = doc.css('tr')[1..-2]
|
421
|
+
result = []
|
422
|
+
rows.each do |row|
|
423
|
+
object = { 'opDate' => date }
|
424
|
+
tds = row.css('td')
|
425
|
+
MAR_SZ_MX_COLS.each_with_index do |key, index|
|
426
|
+
object[key] = tds[index].content.strip
|
427
|
+
end
|
428
|
+
result << object
|
429
|
+
end
|
430
|
+
result
|
431
|
+
end
|
432
|
+
|
433
|
+
private
|
434
|
+
|
435
|
+
def get_data(start_page, headers, doc_generator, row_finder,
|
436
|
+
row_processor, last_page_guard)
|
437
|
+
_write_head
|
438
|
+
[].concat process_data(start_page, headers, doc_generator,
|
439
|
+
row_finder, row_processor, last_page_guard)
|
440
|
+
end
|
441
|
+
|
442
|
+
def process_data(start_page, headers, doc_generator, row_finder,
|
443
|
+
row_processor, last_page_guard)
|
444
|
+
result = []
|
445
|
+
page = start_page
|
446
|
+
loop do
|
447
|
+
_write_console
|
448
|
+
doc = doc_generator.call(page)
|
449
|
+
row_finder.call(doc).each do |tr|
|
450
|
+
object = {}
|
451
|
+
row_processor.call(tr.css('td')).each_with_index do |item, index|
|
452
|
+
object[headers[index]] = item if headers[index]
|
453
|
+
end
|
454
|
+
result << object
|
455
|
+
end
|
456
|
+
break if last_page_guard.call(doc)
|
457
|
+
page += 1
|
458
|
+
end
|
459
|
+
result
|
460
|
+
end
|
461
|
+
|
462
|
+
def _random(n = 13)
|
463
|
+
start_int = 10**(n-1)
|
464
|
+
end_int = (10**n) - 1
|
465
|
+
rand(start_int..end_int).to_s
|
466
|
+
end
|
467
|
+
|
468
|
+
module_function :profit_data, :forecast_data, :fund_holdings, :new_stocks,
|
469
|
+
:sh_margins, :sh_margin_details, :sz_margins, :xsg_data,
|
470
|
+
:sz_margin_details, :get_data, :process_data, :_random
|
471
|
+
end
|
472
|
+
end
|
473
|
+
end
|