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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4bf0d80a7c81bd75a4d9ca26c5571a57938a73fdfd47543ab82e9ea93f42e3f0
4
- data.tar.gz: 9c53d62b2fbcb17700a2f1f4c08586ed218098ad80a9247b6b839486d46829ce
3
+ metadata.gz: 6f517a7bf018413f424a2eba1e1c568c4db864240f88d23fe0c722526af858b4
4
+ data.tar.gz: 7e303f08f4be6d64f1680f5107690e78525edcdf938245b22ab97a38af1523e7
5
5
  SHA512:
6
- metadata.gz: ac6600a7a6f7791df53e631e49f3a4f56e8f2c95801b699dd06510f0b072f7a20d22a8edefbc2b53ef183954c4c13e0889442af2b06911e1ddd3c339217daa3b
7
- data.tar.gz: c30e7df2409407c08433baf345660d1dcaeb24b85a035bc2344d2c401303b0961b7dcf901d6e2c5f98f34f273228df2588a8fd83a4e50b0fbbff61d4b541c7c3
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.9.3
1
+ 0.1.14
@@ -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) + 1.day > File.mtime(quarters_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 unless marked
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
- available_contracts = Dir["#{id_path}/*.csv"].map { |x| x.split('/').last.split('.').first }
69
- available_contracts.sort_by! { |x| x[-7] }.sort_by! { |x| x[-6..-5] }
70
- data = []
71
- available_contracts.each do |c|
72
- provide_daily(id: id, config: config, contract: c).each do |x|
73
- data << x
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
- result = []
77
- data.sort_by { |x| x[:date] }.group_by { |x| x[:date] }.map do |k, v|
78
- v.map { |x| x.delete(:date) }
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
- date.nil? ? result : result.select { |x| x[:date] == date }.first
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
- %i[volume oi].include?(selector)
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
- x[:volume].select do
153
- x[:contract] == k
154
- end
155
- end.size
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
- %i[volume oi].include?(selector)
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
- .group_by { |k, _| k[2] }
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
- ydays = v0.map { |_, v1| Date.parse(v1.last[:date]).yday }
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
- ydays.map! { |x| x > 350 ? x - 366 : x } if ydays.min < 50
246
+ ldays.map! { |x| x > 350 ? x - 366 : x } if ldays.min < 50
203
247
  fday = fdays[fdays.size / 2]
204
- yavg = ydays.reduce(:+) / ydays.size
205
- # a contract is proposed to use after fday - 1, but before ydays.min (green)
206
- # it is warned to user after fday - 1 but before yavg - 1 (red)
207
- # it is warned red >= yavg - 1 and <= yavg + 1
208
- color = if (ytoday >= yavg - 1) && (ytoday <= yavg + 1)
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 > ydays.min) && (ytoday < yavg - 1)
254
+ elsif (ytoday > ldays.min) && (ytoday < lavg - 1)
211
255
  :light_yellow
212
- elsif (ytoday >= (fday > yavg ? 0 : fday - 5)) && (ytoday <= ydays.min)
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
- }\t#{ytoday
222
- }/#{fday
223
- }\t#{format '%5d', ydays.min
224
- }: #{dfm.call(ydays.min)
225
- }\t#{format '%5d', yavg
226
- }: #{dfm.call(yavg)
227
- }\t#{format '%5d', ydays.max
228
- }: #{dfm.call(ydays.max)}".colorize(color)
229
- if debug || (color != :white)
230
- puts output
231
- output_sent << "#{sym[:symbol]}#{month}" unless color == :white
232
- end
233
- early_year ||= output
234
- next unless (debug and debuglevel >= 2)
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
- v0.each do |contract, v1|
237
- puts "\t#{contract
286
+ v0.each do |contract, v1|
287
+ puts "\t#{contract
238
288
  }\t#{v1.first[:date]
239
- }\t#{Date.parse(v1.last[:date]).strftime('%a')
240
- }, #{v1.last[:date]
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 "---- #{output_sent} for #{sym[:symbol]} ---------------"
255
-
304
+ puts "Continuous table show #{output_sent.size} active contracts ( #{output_sent} ) for #{sym[:symbol]} ---------------"
256
305
  end
257
- output_sent
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)
@@ -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
- source[:days] = Cotcube::Bardata.continuous_actual_ml symbol: symbol
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
- -13..-2
89
+ -(last_n/15)..-2
84
90
  when :weeks
85
- -53..-2
91
+ -(last_n/4)..-2
86
92
  when :days
87
- -200..-1
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.9.3
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-02-08 00:00:00.000000000 Z
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