cotcube-bardata 0.1.9.3 → 0.1.14
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 +4 -4
- data/CHANGELOG.md +21 -0
- data/VERSION +1 -1
- data/lib/cotcube-bardata.rb +7 -2
- data/lib/cotcube-bardata/cached.rb +7 -4
- data/lib/cotcube-bardata/daily.rb +111 -61
- data/lib/cotcube-bardata/helpers.rb +4 -0
- data/lib/cotcube-bardata/init.rb +2 -2
- data/lib/cotcube-bardata/provide.rb +4 -3
- data/lib/cotcube-bardata/range_matrix.rb +18 -7
- data/lib/cotcube-bardata/suggest.rb +28 -0
- data/lib/cotcube-bardata/trade_dates.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6f517a7bf018413f424a2eba1e1c568c4db864240f88d23fe0c722526af858b4
|
4
|
+
data.tar.gz: 7e303f08f4be6d64f1680f5107690e78525edcdf938245b22ab97a38af1523e7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5cbeae28346fca35de00cdc926724799f00c69ac8b023075c5dbd332327303ab457e1558eb289979ce95ef31b0cbc7e7cd1439ce550c4b2ddb415c79cffa21dd
|
7
|
+
data.tar.gz: 9fcdc6b0b14212673d1c26e9c5b6b76264a2d8baa7270d609841377ad3fd753bb1011ddad499a27412e180dcbb8bc35a831e79e79c487866634f85533440b771
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,24 @@
|
|
1
|
+
## 0.1.14 (May 07, 2021)
|
2
|
+
- few changes in provide / cached / daily for a more straigtforward forcing of cache renewal
|
3
|
+
- suggest: new method to suggest a contract for given symbol and date
|
4
|
+
|
5
|
+
## 0.1.13 (April 07, 2021)
|
6
|
+
- daily: fixed const_caching in continuous
|
7
|
+
- trade_dates: FIXING call with HTTParty must send Agent Header
|
8
|
+
- helpers/get_id_set: added support for params given as Symbols (:NG instead of 'NG')
|
9
|
+
|
10
|
+
## 0.1.12 (March 13, 2021)
|
11
|
+
- range_matrix: adapted to accept block for range provision; added params :days_only and :last_n
|
12
|
+
- minor fix on previous patch
|
13
|
+
|
14
|
+
## 0.1.11 (March 07, 2021)
|
15
|
+
- daily.rb: added new technique 'caching in constants' to accelerate computation, also referring to continuous
|
16
|
+
- provide.rb: minor change, so disregarded contracts can be used in swapproximate
|
17
|
+
|
18
|
+
## 0.1.10 (February 11, 2021)
|
19
|
+
- Daily.rb: Added measure parameters to continous_suite
|
20
|
+
- cached.rb: Minor fix in comparison
|
21
|
+
|
1
22
|
## 0.1.9.3 (February 08, 2021)
|
2
23
|
- cached: minor change fixing problem to get yesterday in rth subsets
|
3
24
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.14
|
data/lib/cotcube-bardata.rb
CHANGED
@@ -22,6 +22,7 @@ require_relative 'cotcube-bardata/quarters'
|
|
22
22
|
require_relative 'cotcube-bardata/eods'
|
23
23
|
require_relative 'cotcube-bardata/cached'
|
24
24
|
require_relative 'cotcube-bardata/provide'
|
25
|
+
require_relative 'cotcube-bardata/suggest'
|
25
26
|
require_relative 'cotcube-bardata/range_matrix'
|
26
27
|
require_relative 'cotcube-bardata/trading_hours'
|
27
28
|
|
@@ -61,13 +62,17 @@ module Cotcube
|
|
61
62
|
# create an array of ranges based on specified source data
|
62
63
|
:trading_hours,
|
63
64
|
# receive id / symbol information on an uncertain set of parameters
|
65
|
+
# TODO: decommision sppearance of get_id_set and symbols in cotcube::bardata
|
64
66
|
:get_id_set,
|
67
|
+
:symbols,
|
68
|
+
#
|
65
69
|
:select_specific_date,
|
66
70
|
:extended_select_for_range,
|
67
71
|
:provide_cached,
|
72
|
+
:suggest_contract_for,
|
73
|
+
#
|
68
74
|
:compare,
|
69
|
-
:holidays
|
70
|
-
:symbols # reads and provides the symbols file
|
75
|
+
:holidays
|
71
76
|
|
72
77
|
# please note that module_functions of source provided in private files must be published there
|
73
78
|
end
|
@@ -12,7 +12,7 @@ module Cotcube
|
|
12
12
|
timezone: Time.find_zone('America/Chicago'),
|
13
13
|
filter: :full, # most probably either :full or :rth
|
14
14
|
force_update: false, # force reloading via provide_quarters
|
15
|
-
force_recent: false) #
|
15
|
+
force_recent: false) # provide base.last even if dayswitch hasn't happen yet
|
16
16
|
|
17
17
|
unless range.nil? ||
|
18
18
|
range.is_a?(Range) &&
|
@@ -39,6 +39,8 @@ module Cotcube
|
|
39
39
|
file = "#{dir}/#{contract}.csv"
|
40
40
|
quarters_file = "#{config[:data_path]}/quarters/#{sym[:id]}/#{contract[-3..]}.csv"
|
41
41
|
if File.exist?(file) && (not force_update)
|
42
|
+
puts "Working with existing #{file}, no update was forced" if debug
|
43
|
+
puts " Using quarters from #{quarters_file}"
|
42
44
|
base = CSV.read(file, headers: headers).map do |x|
|
43
45
|
x = x.to_h
|
44
46
|
x[:datetime] = timezone.parse(x[:datetime])
|
@@ -49,7 +51,7 @@ module Cotcube
|
|
49
51
|
end
|
50
52
|
if base.last[:high].zero?
|
51
53
|
# contract exists but is closed (has the CLOSED marker)
|
52
|
-
base.pop
|
54
|
+
base.pop
|
53
55
|
# rubocop:disable Metrics/BlockNesting
|
54
56
|
result = if range.nil?
|
55
57
|
base
|
@@ -60,7 +62,7 @@ module Cotcube
|
|
60
62
|
end
|
61
63
|
end
|
62
64
|
return result
|
63
|
-
elsif File.mtime(file)
|
65
|
+
elsif File.mtime(file) - Time.now.beginning_of_day >= 0
|
64
66
|
puts "CACHE #{File.mtime(file)}\t#{file}" if debug
|
65
67
|
puts "QUART #{File.mtime(quarters_file)}\t#{quarters_file}" if debug
|
66
68
|
result = if range.nil?
|
@@ -96,8 +98,9 @@ module Cotcube
|
|
96
98
|
end
|
97
99
|
|
98
100
|
base = Cotcube::Helpers.reduce(bars: data, to: :days)
|
101
|
+
puts "Reduced base ends at #{bast.last[:datetime].strftime('%Y-%m-%d')}" if debug
|
99
102
|
|
100
|
-
# remove last day of result
|
103
|
+
# remove last day of result if suspecting incomplete last base
|
101
104
|
base.pop if base.last[:datetime].to_date == timezone.now.to_date and not force_recent
|
102
105
|
|
103
106
|
base.map do |x|
|
@@ -8,6 +8,7 @@ module Cotcube
|
|
8
8
|
symbol: nil, id: nil,
|
9
9
|
range: nil,
|
10
10
|
timezone: Time.find_zone('America/Chicago'),
|
11
|
+
keep_last: false,
|
11
12
|
config: init)
|
12
13
|
contract = contract.to_s.upcase
|
13
14
|
unless contract.is_a?(String) && [3, 5].include?(contract.size)
|
@@ -48,7 +49,7 @@ module Cotcube
|
|
48
49
|
row[:type] = :daily
|
49
50
|
row
|
50
51
|
end
|
51
|
-
data.pop if data.last[:high].zero?
|
52
|
+
data.pop if data.last[:high].zero? and not keep_last
|
52
53
|
if range.nil?
|
53
54
|
data
|
54
55
|
else
|
@@ -61,29 +62,52 @@ module Cotcube
|
|
61
62
|
|
62
63
|
# reads all files in bardata/daily/<id> and aggregates by date
|
63
64
|
# (what is a pre-stage of a continuous based on daily bars)
|
64
|
-
def continuous(symbol: nil, id: nil, config: init, date: nil)
|
65
|
+
def continuous(symbol: nil, id: nil, config: init, date: nil, measure: nil, force_rewrite: false)
|
66
|
+
raise ArgumentError, ':measure, if given, must be a Time object (e.g. Time.now)' unless [NilClass, Time].include? measure.class
|
67
|
+
measuring = lambda {|c| puts "[continuous] Time measured until '#{c}': #{(Time.now.to_f - measure.to_f).round(2)}sec" unless measure.nil? }
|
68
|
+
|
69
|
+
measuring.call("Starting")
|
65
70
|
sym = get_id_set(symbol: symbol, id: id)
|
66
71
|
id = sym[:id]
|
72
|
+
symbol = sym[:symbol]
|
67
73
|
id_path = "#{config[:data_path]}/daily/#{id}"
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
+
c_file = "#{id_path}/continuous.csv"
|
75
|
+
|
76
|
+
# instead of using the provide_daily methods above, for this bulk operation a 'continuous.csv' is created
|
77
|
+
# this boosts from 4.5sec to 0.3sec
|
78
|
+
rewriting = force_rewrite or not(File.exist?(c_file)) or (Time.now - File.mtime(c_file) > 8.days)
|
79
|
+
if rewriting
|
80
|
+
puts "In daily+continuous: Rewriting #{c_file} #{force_rewrite ? "forcibly" : "due to fileage"}.".light_yellow
|
81
|
+
`rm #{c_file}; find #{id_path} | xargs cat 2>/dev/null | grep -v '0,0,0,0' | sort -t, -k2 | cut -d, -f1,2,7,8 > #{c_file}`
|
82
|
+
end
|
83
|
+
loading = lambda do
|
84
|
+
data = CSV.read(c_file).map do |row|
|
85
|
+
r = { contract: row[0],
|
86
|
+
date: row[1],
|
87
|
+
volume: row[2].to_i,
|
88
|
+
oi: row[3].to_i
|
89
|
+
}
|
74
90
|
end
|
91
|
+
|
92
|
+
measuring.call("Finished retrieving dailies.")
|
93
|
+
result = []
|
94
|
+
data.group_by { |x| x[:date] }.map do |k, v|
|
95
|
+
v.map { |x| x.delete(:date) }
|
96
|
+
result << {
|
97
|
+
date: k,
|
98
|
+
volume: v.map { |x| x[:volume] }.reduce(:+),
|
99
|
+
oi: v.map { |x| x[:oi] }.reduce(:+)
|
100
|
+
}
|
101
|
+
result.last[:contracts] = v
|
102
|
+
end
|
103
|
+
result
|
75
104
|
end
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
result << {
|
80
|
-
date: k,
|
81
|
-
volume: v.map { |x| x[:volume] }.reduce(:+),
|
82
|
-
oi: v.map { |x| x[:oi] }.reduce(:+)
|
83
|
-
}
|
84
|
-
result.last[:contracts] = v
|
105
|
+
constname = "CONTINUOUS_#{symbol}".to_sym
|
106
|
+
if rewriting or not Cotcube::Bardata.const_defined?( constname)
|
107
|
+
Cotcube::Bardata.const_set constname, loading.call
|
85
108
|
end
|
86
|
-
|
109
|
+
measuring.call("Finished processing")
|
110
|
+
date.nil? ? Cotcube::Bardata.const_get(constname).map{|z| z.dup } : Cotcube::Bardata.const_get(constname).find { |x| x[:date] == date }
|
87
111
|
end
|
88
112
|
|
89
113
|
def continuous_ml(symbol: nil, id: nil, base: nil)
|
@@ -116,20 +140,27 @@ module Cotcube
|
|
116
140
|
config: init,
|
117
141
|
selector: :volume,
|
118
142
|
human: false,
|
143
|
+
measure: nil,
|
119
144
|
filter: nil)
|
145
|
+
|
146
|
+
raise ArgumentError, ':measure, if given, must be a Time object (e.g. Time.now)' unless [NilClass, Time].include? measure.class
|
147
|
+
measuring = lambda {|c| puts "[continuous_overview] Time measured until '#{c}': #{(Time.now.to_f - measure.to_f).round(2)}sec" unless measure.nil? }
|
148
|
+
|
120
149
|
raise ArgumentError, 'Selector must be either :volume or :oi' unless selector.is_a?(Symbol) &&
|
121
|
-
|
150
|
+
%i[volume oi].include?(selector)
|
122
151
|
|
152
|
+
measuring.call("Starting")
|
123
153
|
sym = get_id_set(symbol: symbol, id: id)
|
124
154
|
id = sym[:id]
|
125
155
|
# noinspection RubyNilAnalysis
|
126
|
-
data = continuous(id: id, config: config).map do |x|
|
156
|
+
data = continuous(id: id, config: config, measure: measure).map do |x|
|
127
157
|
{
|
128
158
|
date: x[:date],
|
129
159
|
volume: x[:contracts].sort_by { |z| - z[:volume] }[0..4].compact.reject { |z| z[:volume].zero? },
|
130
160
|
oi: x[:contracts].sort_by { |z| - z[:oi] }[0..4].compact.reject { |z| z[:oi].zero? }
|
131
161
|
}
|
132
162
|
end
|
163
|
+
measuring.call("Retrieved continuous for #{sym[:symbol]}")
|
133
164
|
data.reject! { |x| x[selector].empty? }
|
134
165
|
result = data.group_by { |x| x[selector].first[:contract] }
|
135
166
|
result.each_key do |key|
|
@@ -149,14 +180,15 @@ module Cotcube
|
|
149
180
|
}\t#{v.last[:date]
|
150
181
|
}\t#{format('%4d', (Date.parse(v.last[:date]) - Date.parse(v.first[:date])))
|
151
182
|
}\t#{result[k].map do |x|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
183
|
+
x[:volume].select do
|
184
|
+
x[:contract] == k
|
185
|
+
end
|
186
|
+
end.size
|
156
187
|
}"
|
157
188
|
# rubocop:enable Layout/ClosingParenthesisIndentation
|
158
189
|
end
|
159
190
|
end
|
191
|
+
measuring.call("Finished processing")
|
160
192
|
result
|
161
193
|
end
|
162
194
|
|
@@ -164,19 +196,28 @@ module Cotcube
|
|
164
196
|
selector: :volume,
|
165
197
|
filter: nil,
|
166
198
|
date: Date.today,
|
199
|
+
short: true,
|
200
|
+
silent: false,
|
201
|
+
measure: nil,
|
167
202
|
debuglevel: 1,
|
168
203
|
debug: false)
|
169
204
|
if debug.is_a?(Integer)
|
170
205
|
debuglevel = debug
|
171
206
|
debug = debuglevel > 0 ? true : false
|
172
207
|
end
|
208
|
+
silent = false if debug
|
209
|
+
|
210
|
+
raise ArgumentError, ':measure, if given, must be a Time object (e.g. Time.now)' unless [NilClass, Time].include? measure.class
|
211
|
+
measuring = lambda {|c| puts "[continuous_table] Time measured until '#{c}': #{(Time.now.to_f - measure.to_f).round(2)}sec" unless measure.nil? }
|
212
|
+
|
173
213
|
raise ArgumentError, 'Selector must be either :volume or :oi' unless selector.is_a?(Symbol) &&
|
174
|
-
|
214
|
+
%i[volume oi].include?(selector)
|
175
215
|
|
216
|
+
measuring.call("Entering function")
|
176
217
|
sym = get_id_set(symbol: symbol, id: id)
|
177
218
|
if %w[R6 BJ GE].include? sym[:symbol]
|
178
|
-
puts "Rejecting to process symbol '#{sym[:symbol]}'."
|
179
|
-
return
|
219
|
+
puts "Rejecting to process symbol '#{sym[:symbol]}'.".light_red
|
220
|
+
return []
|
180
221
|
end
|
181
222
|
id = sym[:id]
|
182
223
|
dfm = lambda do |x, y = date.year|
|
@@ -188,60 +229,69 @@ module Cotcube
|
|
188
229
|
end
|
189
230
|
|
190
231
|
ytoday = date.yday
|
191
|
-
data = continuous_overview(id: id, selector: selector, filter: filter, human: false, config: init)
|
232
|
+
data = continuous_overview(id: id, selector: selector, filter: filter, human: false, config: init, measure: measure)
|
192
233
|
.reject { |k, _| k[-2..].to_i == date.year % 2000 }
|
193
|
-
|
234
|
+
.group_by { |k, _| k[2] }
|
235
|
+
measuring.call("Retrieved continous_overview")
|
194
236
|
output_sent = []
|
195
237
|
early_year=nil
|
238
|
+
long_output = []
|
196
239
|
data.keys.sort.each do |month|
|
240
|
+
current_long = { month: month }
|
197
241
|
puts "Processing #{sym[:symbol]}#{month}" if debuglevel > 1
|
198
242
|
v0 = data[month]
|
199
|
-
|
243
|
+
ldays = v0.map { |_, v1| Date.parse(v1.last[:date]).yday }
|
200
244
|
fdays = v0.map { |_, v1| Date.parse(v1.first[:date]).yday }.sort
|
201
245
|
# if the last ml day nears the end of the year, we must fix
|
202
|
-
|
246
|
+
ldays.map! { |x| x > 350 ? x - 366 : x } if ldays.min < 50
|
203
247
|
fday = fdays[fdays.size / 2]
|
204
|
-
|
205
|
-
# a contract is proposed to use after fday - 1, but before
|
206
|
-
# it is warned to user after fday - 1 but before
|
207
|
-
# it is warned red >=
|
208
|
-
color = if (ytoday >=
|
248
|
+
lavg = ldays.reduce(:+) / ldays.size
|
249
|
+
# a contract is proposed to use after fday - 1, but before ldays.min (green)
|
250
|
+
# it is warned to user after fday - 1 but before lavg - 1 (red)
|
251
|
+
# it is warned red >= lavg - 1 and <= lavg + 1
|
252
|
+
color = if (ytoday >= lavg - 1) && (ytoday <= lavg + 1)
|
209
253
|
:light_red
|
210
|
-
elsif (ytoday >
|
254
|
+
elsif (ytoday > ldays.min) && (ytoday < lavg - 1)
|
211
255
|
:light_yellow
|
212
|
-
elsif (ytoday >= (fday >
|
256
|
+
elsif (ytoday >= (fday > lavg ? 0 : fday - 5)) && (ytoday <= ldays.min)
|
213
257
|
:light_green
|
214
258
|
else
|
215
259
|
:white
|
216
260
|
end
|
217
261
|
# rubocop:disable Layout/ClosingParenthesisIndentation
|
262
|
+
long_output << {
|
263
|
+
month: month,
|
264
|
+
first_ml: fday,
|
265
|
+
last_min: ldays.min,
|
266
|
+
last_avg: lavg,
|
267
|
+
last_max: ldays.max }
|
218
268
|
output = "#{sym[:symbol]
|
219
269
|
}#{month
|
220
270
|
}\t#{format '%12s', sym[:type]
|
221
|
-
}\
|
222
|
-
|
223
|
-
}\
|
224
|
-
}: #{dfm.call(
|
225
|
-
}\t#{format '%5d',
|
226
|
-
}: #{dfm.call(
|
227
|
-
}\
|
228
|
-
}: #{dfm.call(
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
271
|
+
}\ttoday is #{ytoday
|
272
|
+
} -- median of first is #{fday
|
273
|
+
}\tlast ranges from #{format '%5d', ldays.min
|
274
|
+
}: #{dfm.call(ldays.min)
|
275
|
+
}\t#{format '%5d', lavg
|
276
|
+
}: #{dfm.call(lavg)
|
277
|
+
}\tto #{format '%5d', ldays.max
|
278
|
+
}: #{dfm.call(ldays.max)}".colorize(color)
|
279
|
+
if debug || (color != :white)
|
280
|
+
puts output
|
281
|
+
output_sent << "#{sym[:symbol]}#{month}" unless color == :white
|
282
|
+
end
|
283
|
+
early_year ||= output
|
284
|
+
next if silent or not (debug and debuglevel >= 2)
|
235
285
|
|
236
|
-
|
237
|
-
|
286
|
+
v0.each do |contract, v1|
|
287
|
+
puts "\t#{contract
|
238
288
|
}\t#{v1.first[:date]
|
239
|
-
}
|
240
|
-
|
241
|
-
} (#{Date.parse(v1.last[:date]).yday}"
|
289
|
+
} (#{format '%3d', Date.parse(v1.first[:date]).yday
|
290
|
+
})\t#{Date.parse(v1.last[:date]).strftime('%a, %Y-%m-%d')
|
291
|
+
} (#{Date.parse(v1.last[:date]).yday})"
|
242
292
|
# rubocop:enable Layout/ClosingParenthesisIndentation
|
293
|
+
end
|
243
294
|
end
|
244
|
-
end
|
245
295
|
case output_sent.size
|
246
296
|
when 0
|
247
297
|
puts "WARNING: No output was sent for symbol '#{sym[:symbol]}'.".colorize(:light_yellow)
|
@@ -251,10 +301,10 @@ module Cotcube
|
|
251
301
|
# all ok
|
252
302
|
true
|
253
303
|
else
|
254
|
-
puts "
|
255
|
-
|
304
|
+
puts "Continuous table show #{output_sent.size} active contracts ( #{output_sent} ) for #{sym[:symbol]} ---------------"
|
256
305
|
end
|
257
|
-
|
306
|
+
measuring.call("Finished processing")
|
307
|
+
short ? output_sent : long_output
|
258
308
|
end
|
259
309
|
end
|
260
310
|
end
|
@@ -46,6 +46,10 @@ module Cotcube
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def get_id_set(symbol: nil, id: nil, contract: nil, config: init)
|
49
|
+
contract = contract.to_s.upcase if contract.is_a? Symbol
|
50
|
+
id = id.to_s.upcase if id.is_a? Symbol
|
51
|
+
symbol = symbol.to_s.upcase if symbol.is_a? Symbol
|
52
|
+
|
49
53
|
if contract.is_a?(String) && (contract.length == 5)
|
50
54
|
c_symbol = contract[0..1]
|
51
55
|
if (not symbol.nil?) && (symbol != c_symbol)
|
data/lib/cotcube-bardata/init.rb
CHANGED
@@ -8,9 +8,9 @@ module Cotcube
|
|
8
8
|
SYMBOL_EXAMPLES
|
9
9
|
else
|
10
10
|
CSV
|
11
|
-
.read(config[:symbols_file], headers: %i[id symbol ticksize power months type bcf reports name])
|
11
|
+
.read(config[:symbols_file], headers: %i[id symbol ticksize power months type bcf reports format name])
|
12
12
|
.map(&:to_h)
|
13
|
-
.map { |row| %i[ticksize power bcf].each { |z| row[z] = row[z].to_f }; row } # rubocop:disable Style/Semicolon
|
13
|
+
.map { |row| %i[ticksize power bcf].each { |z| row[z] = row[z].to_f }; row[:format] = "%#{row[:format]}f"; row } # rubocop:disable Style/Semicolon
|
14
14
|
.reject { |row| row[:id].nil? }
|
15
15
|
.tap { |all| all.select! { |x| x[:type] == type } unless type.nil? }
|
16
16
|
.tap { |all| all.select! { |x| x[:symbol] == symbol } unless symbol.nil? }
|
@@ -14,6 +14,7 @@ module Cotcube
|
|
14
14
|
filter: :full,
|
15
15
|
# TODO: for future compatibility and suggestion: planning to include a function to update
|
16
16
|
# with live data from broker
|
17
|
+
force_update: false,
|
17
18
|
force_recent: false)
|
18
19
|
|
19
20
|
sym = get_id_set(symbol: symbol, id: id, contract: contract, config: config)
|
@@ -33,7 +34,7 @@ module Cotcube
|
|
33
34
|
|
34
35
|
when :days, :weeks, :months
|
35
36
|
base = provide_cached contract: contract, symbol: symbol, id: id, config: config, filter: filter,
|
36
|
-
range: range, force_recent: force_recent
|
37
|
+
range: range, force_recent: force_recent, force_update: force_update
|
37
38
|
return base if %i[day days].include? interval
|
38
39
|
|
39
40
|
# TODO: Missing implementation to reduce cached days to weeks or months
|
@@ -42,9 +43,9 @@ module Cotcube
|
|
42
43
|
provide_daily contract: contract, symbol: symbol, id: id, config: config, range: range
|
43
44
|
when :synth, :synthetic, :synthetic_days
|
44
45
|
days = provide_cached contract: contract, symbol: symbol, id: id, config: config, filter: filter,
|
45
|
-
range: range, force_recent: force_recent
|
46
|
+
range: range, force_recent: force_recent, force_update: force_update
|
46
47
|
dailies = provide_daily contract: contract, symbol: symbol, id: id, config: config, range: range
|
47
|
-
if days.last[:datetime] > dailies.last[:datetime]
|
48
|
+
if ((days.last[:datetime] > dailies.last[:datetime]) rescue false)
|
48
49
|
dailies[..-2] + days.select { |d| d[:datetime] > dailies[-2][:datetime] }
|
49
50
|
else
|
50
51
|
dailies
|
@@ -5,7 +5,6 @@ module Cotcube
|
|
5
5
|
module Bardata
|
6
6
|
# this is an analysis tool to investigate actual ranges of an underlying symbol
|
7
7
|
# it is in particular no true range or average true range, as a 'true range' can only be applied to
|
8
|
-
# a steady series, what changing contracts definitely aren't
|
9
8
|
#
|
10
9
|
# The result printed / returned is a table, containing a matrix of rows:
|
11
10
|
# 1. size: the amount of values evaluated
|
@@ -22,18 +21,25 @@ module Cotcube
|
|
22
21
|
# 3.a-c) same with days reduced to months (c: 12 months)
|
23
22
|
#
|
24
23
|
# NOTE: there is now a new method Cotcube::Helpers.simple_series_stats, that should be used in favor.
|
25
|
-
def range_matrix(symbol: nil, id: nil, print: false, dim: 0.05)
|
24
|
+
def range_matrix(symbol: nil, id: nil, base: nil, print: false, dim: 0.05, days_only: false, last_n: 60, &block)
|
26
25
|
# rubocop:disable Style/MultilineBlockChain
|
26
|
+
symbol ||= base.last[:contract][0..1] if id.nil?
|
27
27
|
sym = get_id_set(symbol: symbol, id: id)
|
28
28
|
source = {}
|
29
29
|
target = {}
|
30
|
-
|
30
|
+
if base.nil?
|
31
|
+
ml = (Cotcube::Bardata.continuous_actual_ml symbol: symbol)&.last[:contract]
|
32
|
+
source[:days] = Cotcube::Bardata.provide contract: ml
|
33
|
+
else
|
34
|
+
source[:days] = base
|
35
|
+
end
|
31
36
|
source[:weeks] = Cotcube::Helpers.reduce bars: source[:days], to: :weeks
|
32
37
|
source[:months] = Cotcube::Helpers.reduce bars: source[:days], to: :months
|
33
38
|
|
34
39
|
%i[days weeks months].each do |period|
|
40
|
+
next if days_only and %i[weeks months].include? period
|
35
41
|
source[period].map! do |x|
|
36
|
-
x[:range] = ((x[:high] - x[:low]) / sym[:ticksize]).round
|
42
|
+
x[:range] = block_given? ? yield(x) : (((x[:high] - x[:low]) / sym[:ticksize]).round)
|
37
43
|
x
|
38
44
|
end
|
39
45
|
target[period] = {}
|
@@ -80,14 +86,18 @@ module Cotcube
|
|
80
86
|
|
81
87
|
range = case period
|
82
88
|
when :months
|
83
|
-
-
|
89
|
+
-(last_n/15)..-2
|
84
90
|
when :weeks
|
85
|
-
-
|
91
|
+
-(last_n/4)..-2
|
86
92
|
when :days
|
87
|
-
-
|
93
|
+
-last_n..-1
|
88
94
|
else
|
89
95
|
raise ArgumentError, "Unsupported period: '#{period}'"
|
90
96
|
end
|
97
|
+
if range.begin.abs > source[period].size
|
98
|
+
puts "WARNING: requested last_n = #{last_n} exceeds actual size (#{source[period].size}), adjusting...".light_yellow
|
99
|
+
range = (-source[period].size..range.end)
|
100
|
+
end
|
91
101
|
custom = source[period][range]
|
92
102
|
target[period][:rec_size] = custom.size
|
93
103
|
target[period][:rec_avg] = (custom.map { |x| x[:range] }.reduce(:+) / custom.size).round
|
@@ -110,6 +120,7 @@ module Cotcube
|
|
110
120
|
%w[size avg lower median upper max].each do |a|
|
111
121
|
print "#{'%10s' % a} | " # rubocop:disable Style/FormatString
|
112
122
|
%i[days weeks months].each do |b|
|
123
|
+
next if days_only and %i[weeks months].include? b
|
113
124
|
%w[all dim rec].each do |c|
|
114
125
|
print ('%8d' % target[b]["#{c}_#{a}".to_sym]).to_s # rubocop:disable Style/FormatString
|
115
126
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cotcube
|
4
|
+
# missing top level documentation
|
5
|
+
module Bardata
|
6
|
+
# based on day(of year) and symbol, suggest best fitting contract
|
7
|
+
def suggest_contract_for symbol:, date: Date.today, warnings: true
|
8
|
+
ml = Cotcube::Bardata.continuous_table symbol: symbol, date: date
|
9
|
+
if ml.size != 1
|
10
|
+
puts "WARNING: No or no unique most liquid found for #{date}. please give :contract parameter".light_yellow if warnings
|
11
|
+
if ml.size > 1
|
12
|
+
puts "\tUsing #{ml.last}. Consider breaking here, if that is not acceptable.".light_yellow if warnings
|
13
|
+
sleep 1
|
14
|
+
else
|
15
|
+
puts "\tERROR: No suggestible contract found for #{symbol} and #{date}.".light_red
|
16
|
+
return
|
17
|
+
end
|
18
|
+
end
|
19
|
+
year = date.year % 100
|
20
|
+
if ml.last[2] < "K" and date.month > 9
|
21
|
+
"#{ml.last}#{year + 1}"
|
22
|
+
else
|
23
|
+
"#{ml.last}#{year}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
@@ -8,7 +8,7 @@ module Cotcube
|
|
8
8
|
def last_trade_date
|
9
9
|
uri = 'https://www.cmegroup.com/CmeWS/mvc/Volume/TradeDates?exchange=CME'
|
10
10
|
begin
|
11
|
-
HTTParty.get(uri)
|
11
|
+
HTTParty.get(uri, headers: { "User-Agent" => "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/81.0"})
|
12
12
|
.parsed_response
|
13
13
|
.map do |x|
|
14
14
|
a = x['tradeDate'].chars.each_slice(2).map(&:join)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cotcube-bardata
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.14
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Benjamin L. Tischendorf
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-05-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -175,6 +175,7 @@ files:
|
|
175
175
|
- lib/cotcube-bardata/provide.rb
|
176
176
|
- lib/cotcube-bardata/quarters.rb
|
177
177
|
- lib/cotcube-bardata/range_matrix.rb
|
178
|
+
- lib/cotcube-bardata/suggest.rb
|
178
179
|
- lib/cotcube-bardata/trade_dates.rb
|
179
180
|
- lib/cotcube-bardata/trading_hours.rb
|
180
181
|
homepage: https://github.com/donkeybridge/cotcube-bardata
|