cotcube-level 0.2.0 → 0.3.4
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 +49 -0
- data/README.md +14 -6
- data/VERSION +1 -1
- data/cotcube-level.gemspec +1 -1
- data/lib/cotcube-level/detect_slope.rb +79 -98
- data/lib/cotcube-level/{stencil.rb → eod_stencil.rb} +26 -16
- data/lib/cotcube-level/helpers.rb +198 -74
- data/lib/cotcube-level/intraday_stencil.rb +213 -0
- data/lib/cotcube-level/tritangulate.rb +332 -0
- data/lib/cotcube-level.rb +17 -14
- metadata +6 -6
- data/.irbrc.rb +0 -12
- data/lib/cotcube-level/triangulate.rb +0 -238
@@ -0,0 +1,332 @@
|
|
1
|
+
module Cotcube
|
2
|
+
module Level
|
3
|
+
def tritangulate(
|
4
|
+
contract: nil, # contract actually isnt needed for tritangulation, but allows much more convenient output
|
5
|
+
# on some occasion here can also be given a :symbol, but this requires :sym to be set
|
6
|
+
sym: nil, # sym is the id set provided by Cotcube::Helper.get_id_set
|
7
|
+
side:, # :upper or :lower
|
8
|
+
base:, # the base of a readily injected stencil
|
9
|
+
range: (0..-1), # range is relative to base
|
10
|
+
max: 90, # the range which to scan for swaps goes from deg 0 to max
|
11
|
+
debug: false,
|
12
|
+
min_rating: 3, # 1st criteria: swaps having a lower rating are discarded
|
13
|
+
min_length: 8, # 2nd criteria: shorter swaps are discared
|
14
|
+
min_ratio: # 3rd criteria: the ratio between rating and length (if true, swap is discarded)
|
15
|
+
lambda {|r,l| r < l / 4.0 },
|
16
|
+
save: true, # allow saving of results
|
17
|
+
cached: true, # allow loading of cached results
|
18
|
+
interval: , # interval (currently) is one of %i[ daily continuous halfs ]
|
19
|
+
swap_type: nil, # if not given, a warning is printed and swaps won't be saved or loaded
|
20
|
+
with_flaws: 0, # the maximum amount of consecutive bars that would actually break the current swap
|
21
|
+
# should be set to 0 for dailies and I suggest no more than 3 for intraday
|
22
|
+
manual: false, # some triggers must be set differently when manual entry is used
|
23
|
+
deviation: 2 # the maximum shift of :x-values of found members
|
24
|
+
)
|
25
|
+
|
26
|
+
raise ArgumentError, "'0 < max < 90, but got '#{max}'" unless max.is_a? Numeric and 0 < max and max <= 90
|
27
|
+
raise ArgumentError, 'need :side either :upper or :lower for dots' unless [:upper, :lower].include? side
|
28
|
+
|
29
|
+
###########################################################################################################################
|
30
|
+
# init some helpers
|
31
|
+
#
|
32
|
+
high = side == :upper
|
33
|
+
first = base.to_a.find{|x| not x[:high].nil? }
|
34
|
+
zero = base.select{|x| x[:x].zero? }
|
35
|
+
raise ArgumentError, "Inappropriate base, it should contain ONE :x.zero, but contains #{zero.size}." unless zero.size==1
|
36
|
+
zero = zero.first
|
37
|
+
|
38
|
+
contract ||= zero[:contract]
|
39
|
+
sym ||= Cotcube::Helpers.get_id_set(contract: contract)
|
40
|
+
|
41
|
+
|
42
|
+
if cached
|
43
|
+
if interval.nil? or swap_type.nil?
|
44
|
+
puts "Warning: Cannot use cache as both :interval and :swap_type must be given".light_yellow
|
45
|
+
else
|
46
|
+
cache = load_swaps(interval: interval, swap_type: swap_type, contract: contract, sym: sym, datetime: zero[:datetime])
|
47
|
+
# if the current datetime was already processed but nothing has been found,
|
48
|
+
# an 'empty' value is saved.
|
49
|
+
# that means, if neither a swap (or more) nor :empty is found, the datetime has not been processed yet
|
50
|
+
selected = cache.select{|sw| sw[:datetime] == zero[:datetime] and sw[:side] == side }
|
51
|
+
unless selected.empty?
|
52
|
+
puts 'cache_hit'.light_white if debug
|
53
|
+
return (selected.first[:empty] ? [] : selected )
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
###########################################################################################################################
|
59
|
+
# prepare base (i.e. dupe the original, create proper :y, and reject unneeded items)
|
60
|
+
#
|
61
|
+
base = base.
|
62
|
+
map { |x|
|
63
|
+
y = x.dup
|
64
|
+
y[:y] = (high ?
|
65
|
+
(y[:high] - zero[:high]).round(8) :
|
66
|
+
(zero[:low] - y[:low]).round(8)
|
67
|
+
) unless y[:high].nil?
|
68
|
+
y
|
69
|
+
}.
|
70
|
+
reject{|b| b.nil? or b[:datetime] < first[:datetime] or b[:x] < 0 or b[:y].nil?}[range]
|
71
|
+
|
72
|
+
# abs_peak is the absolute high / low of the base. the shearing operation ends there,
|
73
|
+
# but results might be influenced when abs_peak becomes affected by :with_flaws
|
74
|
+
unless manual
|
75
|
+
abs_peak = base.send(high ? :max_by : :min_by){|x| x[high ? :high : :low] }[:datetime]
|
76
|
+
base.reject!{|x| x[:datetime] < abs_peak}
|
77
|
+
end
|
78
|
+
|
79
|
+
###########################################################################################################################z
|
80
|
+
# only if (and only if) the range portion above change the underlying base
|
81
|
+
# the offset has to be fixed for :x and :y
|
82
|
+
|
83
|
+
unless range == (0..-1)
|
84
|
+
puts "adjusting range to '#{range}'".light_yellow if debug
|
85
|
+
offset_x = base.last[:x]
|
86
|
+
offset_y = base.last[:y]
|
87
|
+
base.map!{|b| b[:x] -= offset_x; b[:y] -= offset_y ; b}
|
88
|
+
end
|
89
|
+
|
90
|
+
###########################################################################################################################
|
91
|
+
# introducing :i to the base, which provides the negative index of the :base Array of the current element
|
92
|
+
# this simplifies handling during the, where I can use the members array,
|
93
|
+
# that will carry just the index of the original base, regardless how many array_members have be already dropped
|
94
|
+
base.each_index.map{|i| base[i][:i] = -base.size + i }
|
95
|
+
|
96
|
+
|
97
|
+
###########################################################################################################################
|
98
|
+
# LAMBDA no1: simplifying DEBUG output
|
99
|
+
#
|
100
|
+
present = lambda {|z| z.slice(*%i[datetime high low x y i yy dx dev near miss dev]) }
|
101
|
+
|
102
|
+
|
103
|
+
###########################################################################################################################
|
104
|
+
# LAMBDA no2: all members except the pivot itself now most probably are too far to the left
|
105
|
+
# finalizing tries to get the proper dx value for them
|
106
|
+
#
|
107
|
+
finalize = lambda do |results|
|
108
|
+
results.map do |result|
|
109
|
+
result[:members].each do |member|
|
110
|
+
next if member[:yy].nil? or member[:yy].round(PRECISION-5).zero?
|
111
|
+
|
112
|
+
diff = (member[:x] - member[:dx]).abs / 2.0
|
113
|
+
member[:dx] = member[:x] + diff
|
114
|
+
# it employs another binary-search
|
115
|
+
while member[:yy].round(PRECISION-5) != 0.0
|
116
|
+
member[:yy] = shear_to_deg(deg: result[:deg], base: [ member ] ).first[:yy]
|
117
|
+
diff /= 2.0
|
118
|
+
if member[:yy] > 0
|
119
|
+
member[:dx] += diff
|
120
|
+
else
|
121
|
+
member[:dx] -= diff
|
122
|
+
end
|
123
|
+
end
|
124
|
+
member[:yy] = member[:yy].abs.round(PRECISION-5)
|
125
|
+
end
|
126
|
+
|
127
|
+
puts 'done!'.magenta if debug
|
128
|
+
result[:members].each {|member| puts "finalizing #{member}".magenta } if debug
|
129
|
+
result
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
###########################################################################################################################
|
134
|
+
# LAMDBA no3: the actual 'function' to retrieve the slope
|
135
|
+
#
|
136
|
+
# the idea implemented is based on the fact, that we don't know in which exact time of the interval the value
|
137
|
+
# was created. even further we know that the stencil might be incorrect. so after shearing the :x value of the
|
138
|
+
# recently found new member(s) is shifted by :deviation and shearing is repeated. this is done as long as new members
|
139
|
+
# are found.
|
140
|
+
get_slope = lambda do |b|
|
141
|
+
if debug
|
142
|
+
puts "in get_slope ... SETTING BASE: ".light_green
|
143
|
+
puts "Last: \t#{present.call b.last }".light_green
|
144
|
+
puts "First:\t#{present.call b.first}".light_green
|
145
|
+
end
|
146
|
+
members = [ b.last[:i] ]
|
147
|
+
loop do
|
148
|
+
current_slope = detect_slope(base: b, ticksize: sym[:ticksize], format: sym[:format], debug: debug)
|
149
|
+
if debug
|
150
|
+
puts "CURR: #{current_slope[:deg]} "
|
151
|
+
current_slope[:members].each {|x| puts "CURR: #{present.call(x)}" }
|
152
|
+
end
|
153
|
+
current_members = current_slope[:members].map{|dot| dot[:i]}
|
154
|
+
new_members = current_members - members
|
155
|
+
puts "New members: #{new_members} (as of #{current_members} - #{members})" if debug
|
156
|
+
# the return condition is if no new members are found in slope
|
157
|
+
# except lowest members are neighbours, what (recursively) causes re-run until the
|
158
|
+
# first member is solitary
|
159
|
+
if new_members.empty?
|
160
|
+
mem_sorted=members.sort
|
161
|
+
if mem_sorted[1] == mem_sorted[0] + 1 and not manual
|
162
|
+
b2 = b[mem_sorted[1]..mem_sorted[-1]].map{|x| x.dup; x[:dx] = nil; x}
|
163
|
+
puts 'starting recursive rerun'.light_red if debug
|
164
|
+
alternative_slope = get_slope.call(b2)
|
165
|
+
alternative = alternative_slope[:members].map{|bar| bar[:i]}
|
166
|
+
# the alternative won't be used if it misses out a member that would have
|
167
|
+
# been in the 'original' slope
|
168
|
+
if (mem_sorted[1..-1] - alternative).empty?
|
169
|
+
current_slope = alternative_slope
|
170
|
+
members = alternative
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
current_slope[:raw] = members.map{|i| base[i][:x]}
|
175
|
+
|
176
|
+
members.sort_by{|i| -i}.each_with_index do |i, index|
|
177
|
+
|
178
|
+
puts "#{index}\t#{range}\t#{present.call b[i]}".light_yellow if debug
|
179
|
+
|
180
|
+
current_slope[:members] << b[i] unless current_slope[:members].map{|x| x[:datetime]}.include? b[i][:datetime]
|
181
|
+
current_slope[:members].sort_by!{|x| x[:datetime]}
|
182
|
+
end
|
183
|
+
return current_slope
|
184
|
+
|
185
|
+
end
|
186
|
+
# all new members found in current iteration have now receive their new :x value, depending on their distance to
|
187
|
+
# to the origin. when exploring near distance, it is assumned, that the actual :y value might have an
|
188
|
+
# additional distance of 1, further distant points can be distant even :deviation, what defaults to 2
|
189
|
+
# covering e.g. a holiday when using a daily base
|
190
|
+
new_members.each do |mem|
|
191
|
+
current_deviation = (0.1 * b[mem][:x])
|
192
|
+
current_deviation = 1 if current_deviation < 1
|
193
|
+
current_deviation = deviation if current_deviation > deviation
|
194
|
+
b[mem][:dx] = b[mem][:x] + current_deviation
|
195
|
+
end
|
196
|
+
members += new_members
|
197
|
+
end
|
198
|
+
end # of lambda
|
199
|
+
|
200
|
+
###########################################################################################################################
|
201
|
+
# Lambda no. 4: analyzing the slope, adding near misses and characteristics
|
202
|
+
#
|
203
|
+
# near misses are treated as full members, as for example stacked orders within a swap architecture might impede that the
|
204
|
+
# peak runs to the maximum expansion
|
205
|
+
#
|
206
|
+
# first, the swap_base is created by shearing the entire base to current :deg
|
207
|
+
# then all base members are selected that fit the desired :y range.
|
208
|
+
# please note that here also the processing of :with_flaws takes place
|
209
|
+
#
|
210
|
+
# the key :dev is introduced, which is actually a ticksize-based variant of :yy
|
211
|
+
|
212
|
+
analyze = lambda do |swaps|
|
213
|
+
swaps.each do |swap|
|
214
|
+
|
215
|
+
swap_base = base.map{|y|
|
216
|
+
x = y.slice(*%i[ datetime high low dist x y i yy dx ])
|
217
|
+
current_member = swap[:members].find{|z| z[:datetime] == x[:datetime] }
|
218
|
+
x[:dx] = current_member[:dx] if current_member
|
219
|
+
x
|
220
|
+
}
|
221
|
+
swap_base = shear_to_deg(base: swap_base, deg: swap[:deg])
|
222
|
+
swap_base.map!{|x| x[:dev] = (x[:yy] / sym[:ticksize].to_f); x[:dev] = -( x[:dev] > 0 ? x[:dev].floor : x[:dev].ceil); x}
|
223
|
+
invalids = swap_base.select{|x| x[:dev] < 0 }
|
224
|
+
with_flaws = 0 unless with_flaws # support legacy versions, where with_flaws was boolean
|
225
|
+
if with_flaws > 0
|
226
|
+
# TODO: this behaves only as expected when with_flaws == 2
|
227
|
+
last_invalid = invalids[(invalids[-2][:i] + 1 == invalids[-1][:i] ) ? -3 : -2] rescue nil
|
228
|
+
else
|
229
|
+
last_invalid = invalids.last
|
230
|
+
end
|
231
|
+
|
232
|
+
# the 'near' members are all base members found, that fit
|
233
|
+
# 1. being positive (as being zero means that they are original members)
|
234
|
+
# 2. match a valid :dev
|
235
|
+
# 3. appeared later than :last_invalid
|
236
|
+
near = swap_base.select{|x|
|
237
|
+
x[:dev] <= [ 5, (x[:x] / 100)+2 ].min and
|
238
|
+
x[:dev].positive? and
|
239
|
+
(last_invalid.nil? ? true : x[:datetime] > last_invalid[:datetime])
|
240
|
+
}.map{|x| x[:near] = x[:dev]; x}
|
241
|
+
|
242
|
+
# these then are added to the swap[:members] and for further processing swap_base is cleaned
|
243
|
+
swap[:members] = (swap[:members] + near).sort_by{|x| x[:datetime] }
|
244
|
+
swap_base.select!{|x| x[:datetime] >= swap[:members].first[:datetime]}
|
245
|
+
|
246
|
+
########################################################################33
|
247
|
+
# now swap characteristics are calculated
|
248
|
+
#
|
249
|
+
# avg_dev: the average distance of high or low to the swap_line
|
250
|
+
swap[:avg_dev] = (swap_base.reject{|x| x[:dev].zero?}.map{|x| x[:dev].abs}.reduce(:+) / (swap_base.size - swap[:members].size).to_f).ceil rescue 0
|
251
|
+
# depth: the maximum distance to the swap line
|
252
|
+
swap[:depth] = swap_base.max_by{|x| x[:dev]}[:dev]
|
253
|
+
swap[:interval] = interval
|
254
|
+
swap[:swap_type] = swap_type
|
255
|
+
swap[:raw] = swap[:members].map{|x| x[:x]}.reverse
|
256
|
+
swap[:size] = swap[:members].size
|
257
|
+
swap[:length] = swap[:raw][-1] - swap[:raw][0]
|
258
|
+
# rating: the maximum distance of the 'most middle' point of the swap to the nearer end
|
259
|
+
swap[:rating] = swap[:raw][1..-2].map{ |dot| [ dot - swap[:raw][0], swap[:raw][-1] - dot].min }.max || 0
|
260
|
+
swap[:datetime] = swap[:members].last[:datetime]
|
261
|
+
swap[:side] = side
|
262
|
+
rat = swap[:rating]
|
263
|
+
# color: to simplify human readability a standard set of colors for intraday and eod based swaps
|
264
|
+
swap[:color] = (rat > 75) ? :light_blue : (rat > 30) ? :magenta : (rat > 15) ? :light_magenta : (rat > 7) ? (high ? :light_green : :light_red) : high ? :green : :red
|
265
|
+
unless %i[ daily continuous ].include? interval
|
266
|
+
swap[:color] = ((rat > 150) ? :light_blue : (rat > 80) ? :magenta : (rat > 30) ? :light_magenta : (rat > 15) ? :light_yellow : high ? :green : :red)
|
267
|
+
end
|
268
|
+
swap[:diff] = (swap[:members].last[ high ? :high : :low ] - swap[:members].first[ high ? :high : :low ]).round(8)
|
269
|
+
swap[:ticks] = (swap[:diff] / sym[:ticksize]).to_i
|
270
|
+
# tpi: ticks per interval, how many ticks are passed each :interval
|
271
|
+
swap[:tpi] = (swap[:ticks].to_f / swap[:length]).round(3)
|
272
|
+
# ppi: power per interval, how many $dollar value is passed each :interval
|
273
|
+
swap[:ppi] = (swap[:tpi] * sym[:power]).round(3)
|
274
|
+
end # swap
|
275
|
+
end # lambda
|
276
|
+
|
277
|
+
###########################################################################################################################
|
278
|
+
# after declaring lambdas, the rest is quite few code
|
279
|
+
#
|
280
|
+
# starting with the full range, a valid slope is searched. the found slope defines an interval of the
|
281
|
+
# base array, in which again a (lower) slope can be uncovered.
|
282
|
+
#
|
283
|
+
# this process is repeated while the interval to be processed is large enough (:min_length)
|
284
|
+
current_range = (0..-1) # RANGE set
|
285
|
+
current_slope = { members: [] } # SLOPE reset
|
286
|
+
current_base = base[current_range].map{|z| z.slice(*%i[datetime high low x y i ])} # BASE set
|
287
|
+
current_results = [ ] # RESULTS reset
|
288
|
+
binding.irb if debug
|
289
|
+
while current_base.size >= min_length # LOOP
|
290
|
+
|
291
|
+
puts '-------------------------------------------------------------------------------------' if debug
|
292
|
+
|
293
|
+
while current_base.size >= min_length and current_slope[:members].size < 2
|
294
|
+
|
295
|
+
puts "---- #{current_base.size} #{current_range.to_s.light_yellow} ------" if debug
|
296
|
+
|
297
|
+
# get new slope
|
298
|
+
current_slope = get_slope.call(current_base) # SLOPE call
|
299
|
+
|
300
|
+
# define new range and base
|
301
|
+
next_i = current_slope[:members].select{|z| z[:miss].nil? and z[:near].nil?}[-2]
|
302
|
+
current_range = ((next_i.nil? ? -2 : next_i[:i])+1..-1) # RANGE adjust
|
303
|
+
current_base = base[current_range].map{|z| z.slice(*%i[datetime high low x y i ])} # BASE adjust
|
304
|
+
end
|
305
|
+
puts "Current slope: ".light_yellow + "#{current_slope}" if debug
|
306
|
+
current_results << current_slope if current_slope # RESULTS add
|
307
|
+
current_slope = { members: [] } # SLOPE reset
|
308
|
+
end
|
309
|
+
|
310
|
+
finalize.call(current_results)
|
311
|
+
analyze.call(current_results)
|
312
|
+
binding.irb if debug
|
313
|
+
|
314
|
+
# reject all results that do not suffice
|
315
|
+
current_results.reject!{|swap| swap[:rating] < min_rating or swap[:length] < min_length or min_ratio.call(swap[:rating],swap[:length])}
|
316
|
+
|
317
|
+
#####################################################################################################################3
|
318
|
+
# finally save results for caching and return them
|
319
|
+
if save
|
320
|
+
if interval.nil? or swap_type.nil?
|
321
|
+
puts "WARNING: Cannot save swaps, as both :interval and :swap_type must be given".colorize(:light_yellow)
|
322
|
+
else
|
323
|
+
current_results.map{|sw| mem = sw[:members]; sw[:slope] = (mem.last[:y] - mem.first[:y]) / (mem.last[mem.last[:dx].nil? ? :x : :dx] - mem.first[mem.first[:dx].nil? ? :x : :dx]).to_f }
|
324
|
+
to_save = current_results.empty? ? [ { datetime: zero[:datetime], side: side, empty: true, interval: interval, swap_type: swap_type } ] : current_results
|
325
|
+
save_swaps(to_save, interval: interval, swap_type: swap_type, contract: contract, sym: sym)
|
326
|
+
end
|
327
|
+
end
|
328
|
+
current_results
|
329
|
+
end
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
data/lib/cotcube-level.rb
CHANGED
@@ -12,34 +12,37 @@ require 'json' unless defined?(JSON)
|
|
12
12
|
require 'digest' unless defined?(Digest)
|
13
13
|
require 'cotcube-helpers'
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
%w[ stencil detect_slope triangulate helpers].each do |part|
|
15
|
+
%w[ eod_stencil intraday_stencil detect_slope tritangulate helpers].each do |part|
|
18
16
|
require_relative "cotcube-level/#{part}"
|
19
17
|
end
|
20
18
|
|
21
|
-
|
22
|
-
|
23
19
|
module Cotcube
|
24
20
|
module Level
|
25
21
|
|
26
|
-
PRECISION =
|
27
|
-
INTERVALS = %i[ daily ]
|
22
|
+
PRECISION = 16
|
23
|
+
INTERVALS = %i[ daily continuous hours halfs ]
|
28
24
|
SWAPTYPES = %i[ full ]
|
25
|
+
TIMEZONES = { 'CT' => Time.find_zone('America/Chicago'),
|
26
|
+
'DE' => Time.find_zone('Europe/Berlin') }
|
27
|
+
GLOBAL_SOW = { 'CT' => '0000-1700' }
|
28
|
+
GLOBAL_EOW = { 'CT' => '1700-0000' }
|
29
|
+
GLOBAL_EOD = { 'CT' => '1600-1700' }
|
30
|
+
|
29
31
|
#module_function :init, # checks whether environment is prepared and returns the config hash
|
30
|
-
module_function :detect_slope,
|
31
|
-
:
|
32
|
-
:
|
32
|
+
module_function :detect_slope, # in detect_slope.rb
|
33
|
+
:tritangulate, # in tritangulate.rb
|
34
|
+
:shear_to_deg, # in helpers.rb
|
35
|
+
:shear_to_rad, # same all below
|
33
36
|
:rad2deg,
|
34
37
|
:deg2rad,
|
35
|
-
:
|
38
|
+
:puts_swap,
|
36
39
|
:save_swaps,
|
37
40
|
:get_jsonl_name,
|
38
41
|
:load_swaps,
|
39
|
-
:
|
40
|
-
:
|
42
|
+
:check_exceedance,
|
43
|
+
:member_to_human
|
41
44
|
|
42
|
-
# please note that module_functions of sources provided in
|
45
|
+
# please note that module_functions of sources provided in non-public files must slso be published within these
|
43
46
|
end
|
44
47
|
end
|
45
48
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cotcube-level
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.4
|
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-10-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -108,7 +108,7 @@ dependencies:
|
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0.9'
|
111
|
-
description: A gem to shear a time series, basically serving as a yet
|
111
|
+
description: A gem to shear a time series, basically serving as a yet unseen class
|
112
112
|
of indicators.
|
113
113
|
email:
|
114
114
|
- donkeybridge@jtown.eu
|
@@ -116,7 +116,6 @@ executables: []
|
|
116
116
|
extensions: []
|
117
117
|
extra_rdoc_files: []
|
118
118
|
files:
|
119
|
-
- ".irbrc.rb"
|
120
119
|
- CHANGELOG.md
|
121
120
|
- Gemfile
|
122
121
|
- README.md
|
@@ -124,9 +123,10 @@ files:
|
|
124
123
|
- cotcube-level.gemspec
|
125
124
|
- lib/cotcube-level.rb
|
126
125
|
- lib/cotcube-level/detect_slope.rb
|
126
|
+
- lib/cotcube-level/eod_stencil.rb
|
127
127
|
- lib/cotcube-level/helpers.rb
|
128
|
-
- lib/cotcube-level/
|
129
|
-
- lib/cotcube-level/
|
128
|
+
- lib/cotcube-level/intraday_stencil.rb
|
129
|
+
- lib/cotcube-level/tritangulate.rb
|
130
130
|
homepage: https://github.com/donkeybridge/cotcube-level
|
131
131
|
licenses:
|
132
132
|
- BSD-3-Clause
|
data/.irbrc.rb
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
def verbose_toggle
|
2
|
-
irb_context.echo ? irb_context.echo = false : irb_context.echo = true
|
3
|
-
end
|
4
|
-
|
5
|
-
alias vt verbose_toggle
|
6
|
-
|
7
|
-
$debug = true
|
8
|
-
IRB.conf[:USE_MULTILINE] = false
|
9
|
-
# require 'bundler'
|
10
|
-
# Bundler.require
|
11
|
-
|
12
|
-
require_relative 'lib/cotcube-level'
|