cotcube-bardata 0.1.9.1 → 0.1.12
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 +19 -0
- data/VERSION +1 -1
- data/lib/cotcube-bardata.rb +2 -0
- data/lib/cotcube-bardata/cached.rb +4 -4
- data/lib/cotcube-bardata/daily.rb +95 -46
- data/lib/cotcube-bardata/init.rb +2 -2
- data/lib/cotcube-bardata/provide.rb +5 -1
- data/lib/cotcube-bardata/range_matrix.rb +19 -7
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5607a73308b8d9d7aff10caccdd3785189072a7d5b2a0b37ea0b6d2bd1ebf4f9
|
4
|
+
data.tar.gz: 18bf8b90e2aad0d32a6608037de861d5383df1bd6d8c6b11e903724c91f172df
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3589e6b49ba104aed0177032cd46299c2c0e1db37330e2b869ab6a97f8b81400917bf29ec631cb37b2f35245ece8dcdb147dd56194487d441773d8c79628d38e
|
7
|
+
data.tar.gz: 3be51d9604d9fb1092939b30fa099801c989babae6ec528479d8af5c8b8750e087dc5965f8b05a3cc5d68281a58de93295cba1b2249030a106220b0eea9594bd
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,22 @@
|
|
1
|
+
## 0.1.12 (March 13, 2021)
|
2
|
+
- range_matrix: adapted to accept block for range provision; added params :days_only and :last_n
|
3
|
+
- minor fix on previous patch
|
4
|
+
|
5
|
+
## 0.1.11 (March 07, 2021)
|
6
|
+
- daily.rb: added new technique 'caching in constants' to accelerate computation, also referring to continuous
|
7
|
+
- provide.rb: minor change, so disregarded contracts can be used in swapproximate
|
8
|
+
|
9
|
+
## 0.1.10 (February 11, 2021)
|
10
|
+
- Daily.rb: Added measure parameters to continous_suite
|
11
|
+
- cached.rb: Minor fix in comparison
|
12
|
+
|
13
|
+
## 0.1.9.3 (February 08, 2021)
|
14
|
+
- cached: minor change fixing problem to get yesterday in rth subsets
|
15
|
+
|
16
|
+
## 0.1.9.2 (February 07, 2021)
|
17
|
+
- minor changes
|
18
|
+
- daily#continuous_table: introducing debuglevel
|
19
|
+
|
1
20
|
## 0.1.9.1 (January 29, 2021)
|
2
21
|
- provide: added new interval 'synth', mixing available dailies with synthetic days based on quarters
|
3
22
|
- minor change / cleanup
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.12
|
data/lib/cotcube-bardata.rb
CHANGED
@@ -52,6 +52,8 @@ module Cotcube
|
|
52
52
|
:continuous_actual_ml,
|
53
53
|
# based on continuous, create list of when which contract was most liquid
|
54
54
|
:continuous_overview,
|
55
|
+
# provider estimation of current ML usability
|
56
|
+
:continuous_table,
|
55
57
|
# provide the list of quarters, possibly as hours or days.
|
56
58
|
:provide_quarters,
|
57
59
|
# some statistics to estimate daily volatility of specific contract
|
@@ -60,7 +60,7 @@ module Cotcube
|
|
60
60
|
end
|
61
61
|
end
|
62
62
|
return result
|
63
|
-
elsif File.mtime(file)
|
63
|
+
elsif File.mtime(file) - Time.now.beginning_of_day >= 0
|
64
64
|
puts "CACHE #{File.mtime(file)}\t#{file}" if debug
|
65
65
|
puts "QUART #{File.mtime(quarters_file)}\t#{quarters_file}" if debug
|
66
66
|
result = if range.nil?
|
@@ -98,17 +98,17 @@ module Cotcube
|
|
98
98
|
base = Cotcube::Helpers.reduce(bars: data, to: :days)
|
99
99
|
|
100
100
|
# remove last day of result unless marked
|
101
|
-
base.pop
|
101
|
+
base.pop if base.last[:datetime].to_date == timezone.now.to_date and not force_recent
|
102
102
|
|
103
103
|
base.map do |x|
|
104
|
-
x[:
|
104
|
+
x[:date] = x[:datetime].to_date
|
105
105
|
x[:type] = "#{filter}_day".to_sym
|
106
106
|
x.delete(:day)
|
107
107
|
end
|
108
108
|
CSV.open(file, 'w') do |csv|
|
109
109
|
base.each { |b| csv << b.values_at(*headers) }
|
110
110
|
if contract_is_marked
|
111
|
-
marker = ["#{sym[:symbol]}#{contract}", base.last[:
|
111
|
+
marker = ["#{sym[:symbol]}#{contract}", base.last[:date] + 1.day, 0, 0, 0, 0, 0]
|
112
112
|
csv << marker
|
113
113
|
end
|
114
114
|
end
|
@@ -61,29 +61,51 @@ module Cotcube
|
|
61
61
|
|
62
62
|
# reads all files in bardata/daily/<id> and aggregates by date
|
63
63
|
# (what is a pre-stage of a continuous based on daily bars)
|
64
|
-
def continuous(symbol: nil, id: nil, config: init, date: nil)
|
64
|
+
def continuous(symbol: nil, id: nil, config: init, date: nil, measure: nil, force_rewrite: false)
|
65
|
+
raise ArgumentError, ':measure, if given, must be a Time object (e.g. Time.now)' unless [NilClass, Time].include? measure.class
|
66
|
+
measuring = lambda {|c| puts "[continuous] Time measured until '#{c}': #{(Time.now.to_f - measure.to_f).round(2)}sec" unless measure.nil? }
|
67
|
+
|
68
|
+
measuring.call("Starting")
|
65
69
|
sym = get_id_set(symbol: symbol, id: id)
|
66
70
|
id = sym[:id]
|
67
71
|
id_path = "#{config[:data_path]}/daily/#{id}"
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
72
|
+
c_file = "#{id_path}/continuous.csv"
|
73
|
+
|
74
|
+
# instead of using the provide_daily methods above, for this bulk operation a 'continuous.csv' is created
|
75
|
+
# this boosts from 4.5sec to 0.3sec
|
76
|
+
rewriting = force_rewrite or not(File.exist?(c_file)) or (Time.now - File.mtime(c_file) > 8.days)
|
77
|
+
if rewriting
|
78
|
+
puts "In daily+continuous: Rewriting #{c_file} #{force_rewrite ? "forcibly" : "due to fileage"}.".light_yellow
|
79
|
+
`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}`
|
80
|
+
end
|
81
|
+
loading = lambda do
|
82
|
+
data = CSV.read(c_file).map do |row|
|
83
|
+
r = { contract: row[0],
|
84
|
+
date: row[1],
|
85
|
+
volume: row[2].to_i,
|
86
|
+
oi: row[3].to_i
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
measuring.call("Finished retrieving dailies.")
|
91
|
+
result = []
|
92
|
+
data.group_by { |x| x[:date] }.map do |k, v|
|
93
|
+
v.map { |x| x.delete(:date) }
|
94
|
+
result << {
|
95
|
+
date: k,
|
96
|
+
volume: v.map { |x| x[:volume] }.reduce(:+),
|
97
|
+
oi: v.map { |x| x[:oi] }.reduce(:+)
|
98
|
+
}
|
99
|
+
result.last[:contracts] = v
|
74
100
|
end
|
101
|
+
result
|
75
102
|
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
|
103
|
+
constname = "CONTINUOUS_#{symbol}".to_sym
|
104
|
+
if rewriting or not Cotcube::Bardata.const_defined?( constname)
|
105
|
+
Cotcube::Bardata.const_set constname, loading.call
|
85
106
|
end
|
86
|
-
|
107
|
+
measuring.call("Finished processing")
|
108
|
+
date.nil? ? Cotcube::Bardata.const_get(constname) : Cotcube::Bardata.const_get(constname).find { |x| x[:date] == date }
|
87
109
|
end
|
88
110
|
|
89
111
|
def continuous_ml(symbol: nil, id: nil, base: nil)
|
@@ -116,20 +138,27 @@ module Cotcube
|
|
116
138
|
config: init,
|
117
139
|
selector: :volume,
|
118
140
|
human: false,
|
141
|
+
measure: nil,
|
119
142
|
filter: nil)
|
143
|
+
|
144
|
+
raise ArgumentError, ':measure, if given, must be a Time object (e.g. Time.now)' unless [NilClass, Time].include? measure.class
|
145
|
+
measuring = lambda {|c| puts "[continuous_overview] Time measured until '#{c}': #{(Time.now.to_f - measure.to_f).round(2)}sec" unless measure.nil? }
|
146
|
+
|
120
147
|
raise ArgumentError, 'Selector must be either :volume or :oi' unless selector.is_a?(Symbol) &&
|
121
|
-
|
148
|
+
%i[volume oi].include?(selector)
|
122
149
|
|
150
|
+
measuring.call("Starting")
|
123
151
|
sym = get_id_set(symbol: symbol, id: id)
|
124
152
|
id = sym[:id]
|
125
153
|
# noinspection RubyNilAnalysis
|
126
|
-
data = continuous(id: id, config: config).map do |x|
|
154
|
+
data = continuous(id: id, config: config, measure: measure).map do |x|
|
127
155
|
{
|
128
156
|
date: x[:date],
|
129
157
|
volume: x[:contracts].sort_by { |z| - z[:volume] }[0..4].compact.reject { |z| z[:volume].zero? },
|
130
158
|
oi: x[:contracts].sort_by { |z| - z[:oi] }[0..4].compact.reject { |z| z[:oi].zero? }
|
131
159
|
}
|
132
160
|
end
|
161
|
+
measuring.call("Retrieved continuous")
|
133
162
|
data.reject! { |x| x[selector].empty? }
|
134
163
|
result = data.group_by { |x| x[selector].first[:contract] }
|
135
164
|
result.each_key do |key|
|
@@ -149,31 +178,44 @@ module Cotcube
|
|
149
178
|
}\t#{v.last[:date]
|
150
179
|
}\t#{format('%4d', (Date.parse(v.last[:date]) - Date.parse(v.first[:date])))
|
151
180
|
}\t#{result[k].map do |x|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
181
|
+
x[:volume].select do
|
182
|
+
x[:contract] == k
|
183
|
+
end
|
184
|
+
end.size
|
156
185
|
}"
|
157
186
|
# rubocop:enable Layout/ClosingParenthesisIndentation
|
158
187
|
end
|
159
188
|
end
|
189
|
+
measuring.call("Finished processing")
|
160
190
|
result
|
161
191
|
end
|
162
192
|
|
163
193
|
def continuous_table(symbol: nil, id: nil,
|
164
194
|
selector: :volume,
|
165
195
|
filter: nil,
|
196
|
+
date: Date.today,
|
197
|
+
measure: nil,
|
198
|
+
debuglevel: 1,
|
166
199
|
debug: false)
|
200
|
+
if debug.is_a?(Integer)
|
201
|
+
debuglevel = debug
|
202
|
+
debug = debuglevel > 0 ? true : false
|
203
|
+
end
|
204
|
+
|
205
|
+
raise ArgumentError, ':measure, if given, must be a Time object (e.g. Time.now)' unless [NilClass, Time].include? measure.class
|
206
|
+
measuring = lambda {|c| puts "[continuous_table] Time measured until '#{c}': #{(Time.now.to_f - measure.to_f).round(2)}sec" unless measure.nil? }
|
207
|
+
|
167
208
|
raise ArgumentError, 'Selector must be either :volume or :oi' unless selector.is_a?(Symbol) &&
|
168
|
-
|
209
|
+
%i[volume oi].include?(selector)
|
169
210
|
|
211
|
+
measuring.call("Entering function")
|
170
212
|
sym = get_id_set(symbol: symbol, id: id)
|
171
213
|
if %w[R6 BJ GE].include? sym[:symbol]
|
172
|
-
puts "Rejecting to process symbol '#{sym[:symbol]}'."
|
173
|
-
return
|
214
|
+
puts "Rejecting to process symbol '#{sym[:symbol]}'.".light_red
|
215
|
+
return []
|
174
216
|
end
|
175
217
|
id = sym[:id]
|
176
|
-
dfm = lambda do |x, y =
|
218
|
+
dfm = lambda do |x, y = date.year|
|
177
219
|
k = Date.strptime("#{y} #{x.negative? ? x + 366 : x}", '%Y %j')
|
178
220
|
k -= 1 while [0, 6].include?(k.wday)
|
179
221
|
k.strftime('%a, %Y-%m-%d')
|
@@ -181,13 +223,15 @@ module Cotcube
|
|
181
223
|
puts "#{sym[:symbol]}\t#{x}\t#{y}"
|
182
224
|
end
|
183
225
|
|
184
|
-
ytoday =
|
185
|
-
data = continuous_overview(id: id, selector: selector, filter: filter, human: false, config: init)
|
186
|
-
|
187
|
-
|
188
|
-
|
226
|
+
ytoday = date.yday
|
227
|
+
data = continuous_overview(id: id, selector: selector, filter: filter, human: false, config: init, measure: measure)
|
228
|
+
.reject { |k, _| k[-2..].to_i == date.year % 2000 }
|
229
|
+
.group_by { |k, _| k[2] }
|
230
|
+
measuring.call("Retrieved continous_overview")
|
231
|
+
output_sent = []
|
232
|
+
early_year=nil
|
189
233
|
data.keys.sort.each do |month|
|
190
|
-
puts "Processing #{sym[:symbol]}#{month}" if
|
234
|
+
puts "Processing #{sym[:symbol]}#{month}" if debuglevel > 1
|
191
235
|
v0 = data[month]
|
192
236
|
ydays = v0.map { |_, v1| Date.parse(v1.last[:date]).yday }
|
193
237
|
fdays = v0.map { |_, v1| Date.parse(v1.first[:date]).yday }.sort
|
@@ -207,10 +251,9 @@ module Cotcube
|
|
207
251
|
else
|
208
252
|
:white
|
209
253
|
end
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
}#{month
|
254
|
+
# rubocop:disable Layout/ClosingParenthesisIndentation
|
255
|
+
output = "#{sym[:symbol]
|
256
|
+
}#{month
|
214
257
|
}\t#{format '%12s', sym[:type]
|
215
258
|
}\t#{ytoday
|
216
259
|
}/#{fday
|
@@ -220,22 +263,27 @@ module Cotcube
|
|
220
263
|
}: #{dfm.call(yavg)
|
221
264
|
}\t#{format '%5d', ydays.max
|
222
265
|
}: #{dfm.call(ydays.max)}".colorize(color)
|
223
|
-
|
224
|
-
|
225
|
-
|
266
|
+
if debug || (color != :white)
|
267
|
+
puts output
|
268
|
+
output_sent << "#{sym[:symbol]}#{month}" unless color == :white
|
269
|
+
end
|
270
|
+
early_year ||= output
|
271
|
+
next unless (debug and debuglevel >= 2)
|
226
272
|
|
227
|
-
|
228
|
-
|
273
|
+
v0.each do |contract, v1|
|
274
|
+
puts "\t#{contract
|
229
275
|
}\t#{v1.first[:date]
|
230
276
|
}\t#{Date.parse(v1.last[:date]).strftime('%a')
|
231
277
|
}, #{v1.last[:date]
|
232
278
|
} (#{Date.parse(v1.last[:date]).yday}"
|
233
|
-
|
234
|
-
|
279
|
+
# rubocop:enable Layout/ClosingParenthesisIndentation
|
280
|
+
end
|
235
281
|
end
|
236
|
-
case output_sent
|
282
|
+
case output_sent.size
|
237
283
|
when 0
|
238
284
|
puts "WARNING: No output was sent for symbol '#{sym[:symbol]}'.".colorize(:light_yellow)
|
285
|
+
puts " Assuming late-year-processing.".light_yellow
|
286
|
+
puts early_year.light_green
|
239
287
|
when 1
|
240
288
|
# all ok
|
241
289
|
true
|
@@ -243,7 +291,8 @@ module Cotcube
|
|
243
291
|
puts "---- #{output_sent} for #{sym[:symbol]} ---------------"
|
244
292
|
|
245
293
|
end
|
246
|
-
|
294
|
+
measuring.call("Finished processing")
|
295
|
+
output_sent
|
247
296
|
end
|
248
297
|
end
|
249
298
|
end
|
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? }
|
@@ -44,7 +44,11 @@ module Cotcube
|
|
44
44
|
days = provide_cached contract: contract, symbol: symbol, id: id, config: config, filter: filter,
|
45
45
|
range: range, force_recent: force_recent
|
46
46
|
dailies = provide_daily contract: contract, symbol: symbol, id: id, config: config, range: range
|
47
|
-
|
47
|
+
if ((days.last[:datetime] > dailies.last[:datetime]) rescue false)
|
48
|
+
dailies[..-2] + days.select { |d| d[:datetime] > dailies[-2][:datetime] }
|
49
|
+
else
|
50
|
+
dailies
|
51
|
+
end
|
48
52
|
else
|
49
53
|
raise ArgumentError, "Unsupported or unknown interval '#{interval}' in Bardata.provide"
|
50
54
|
end
|
@@ -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,26 @@ 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
|
41
|
+
p yield(source[period].first)
|
35
42
|
source[period].map! do |x|
|
36
|
-
x[:range] = ((x[:high] - x[:low]) / sym[:ticksize]).round
|
43
|
+
x[:range] = block_given? ? yield(x) : (((x[:high] - x[:low]) / sym[:ticksize]).round)
|
37
44
|
x
|
38
45
|
end
|
39
46
|
target[period] = {}
|
@@ -80,14 +87,18 @@ module Cotcube
|
|
80
87
|
|
81
88
|
range = case period
|
82
89
|
when :months
|
83
|
-
-
|
90
|
+
-(last_n/15)..-2
|
84
91
|
when :weeks
|
85
|
-
-
|
92
|
+
-(last_n/4)..-2
|
86
93
|
when :days
|
87
|
-
-
|
94
|
+
-last_n..-1
|
88
95
|
else
|
89
96
|
raise ArgumentError, "Unsupported period: '#{period}'"
|
90
97
|
end
|
98
|
+
if range.begin.abs > source[period].size
|
99
|
+
puts "WARNING: requested last_n = #{last_n} exceeds actual size (#{source[period].size}), adjusting...".light_yellow
|
100
|
+
range = (-source[period].size..range.end)
|
101
|
+
end
|
91
102
|
custom = source[period][range]
|
92
103
|
target[period][:rec_size] = custom.size
|
93
104
|
target[period][:rec_avg] = (custom.map { |x| x[:range] }.reduce(:+) / custom.size).round
|
@@ -110,6 +121,7 @@ module Cotcube
|
|
110
121
|
%w[size avg lower median upper max].each do |a|
|
111
122
|
print "#{'%10s' % a} | " # rubocop:disable Style/FormatString
|
112
123
|
%i[days weeks months].each do |b|
|
124
|
+
next if days_only and %i[weeks months].include? b
|
113
125
|
%w[all dim rec].each do |c|
|
114
126
|
print ('%8d' % target[b]["#{c}_#{a}".to_sym]).to_s # rubocop:disable Style/FormatString
|
115
127
|
end
|
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.12
|
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-03-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|