cotcube-level 0.2.0 → 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- 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'
|