cotcube-level 0.3.4.1 → 0.3.4.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 71bc6b4ca29ab4ff089b95568a0d592d4bc2b3d8c1824ea9158d661792f1c5b7
4
- data.tar.gz: 670d5a69457411fc7539542a1bd0ad1712ef9111f7b5a876b3c7bdd5d6de90c0
3
+ metadata.gz: 4bbf4fc1b2edf64ffee60a29ffe7d72a71a4c0f8fb99b889026dce9dbca7399f
4
+ data.tar.gz: 59469c2431a20e9e1f07a99e0af61a4fed59ca276a02d654a2f2bd28a8543c04
5
5
  SHA512:
6
- metadata.gz: 3221bf00e3532ae51f62d98f191332273a2241ae34f0eff99e9840f28f41e339a816d23d100150aca70719855c6a1d0507f6509f2598cad75c880f86089286b3
7
- data.tar.gz: 652072c05872418b438ca7ac937e3e5735a5967804c0d0e8f75b4e5381553b55e8b64ecf769cb820745650717077eae1ac7b0b844325725a1c0c78b6b2fbbf85
6
+ metadata.gz: 78a4cb1a3bc80de5086befc5e927cafc86c38ef62410c4fc9d61e716e929f3847ad4a6ac870d30b94168e10dd72d22267aba8d4d4ae2f52a5e7170454a6864f5
7
+ data.tar.gz: 79ed8087a1936cef86257e24c9909f8923902be09e43868ce29deb5b178d03c2d3bbb2700f2bb76f67b2a58a51df930b3bdd41c4134922ed90bd6b2a1f0990ad
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## 0.3.4.2 (November 28, 2021)
2
+ - added 2 executables to bin to display eod- and intraday-swaps
3
+ - helpers: adding ignorance to load_swaps and other, adding .mark_ignored
4
+ - intraday_stencil: allowing absence of :zero in #use
5
+
1
6
  ## 0.3.4.1 (October 09, 2021)
2
7
  - intraday_stencil: fixing @index, that did not work when used outside active hours
3
8
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.4.1
1
+ 0.3.4.2
data/bin/iswaps.rb ADDED
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/cotcube-level.rb'
4
+
5
+ HELP = <<HEREDOC
6
+ Display current intraday swaps.
7
+ > USAGE: iswaps.rb <contract> [json]
8
+ > contract a contract known to the system
9
+ > json switch to toggle json output instead of human readable
10
+ HEREDOC
11
+ if ARGV.empty?
12
+ puts HELP
13
+ exit
14
+ end
15
+
16
+ contract = ARGV[0].nil? ? nil : ARGV[0].upcase
17
+ json = ARGV.include? 'json'
18
+
19
+ sym = Cotcube::Helpers.get_id_set(contract: contract) rescue "Could not determine contract #{contract}"
20
+ if sym.is_a? Sring; puts sym; puts HELP; exit 1; end
21
+
22
+ swaps = Cotcube::Level::load_swaps(interval: 30.minutes, swap_type: :full, contract: contract, sym: sym).
23
+ select{|swap| not(swap[:empty]) and
24
+ not(swap[:ignored]) and
25
+ not(swap[:exceeded].presence ? (swap[:exceeded] < DateTime.now - 2.days) : false)
26
+ }
27
+ stencil = Cotcube::Level::Intraday_Stencil.new( interval: 30.minutes, swap_type: :full, asset: contract[..1])
28
+ swaps.map!{|swap| stencil.use with: swap, sym: sym}
29
+
30
+ if json
31
+ puts swaps.to_json
32
+ else
33
+ puts '<none>' if swaps.empty?
34
+ swaps.each {|swap|
35
+ notice = if swap[:exceeded]
36
+ "EXCEEDED #{swap[:exceeded]}"
37
+ elsif swap[:ignored]
38
+ 'IGNORED'
39
+ else
40
+ "Current: #{format sym[:format], swap[:current_value]}"
41
+ end
42
+ Cotcube::Level.puts_swap(swap, format: sym[:format], notice: notice)
43
+ }
44
+ end
45
+
data/bin/swaps.rb ADDED
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/cotcube-level.rb'
4
+
5
+ HELP = <<HEREDOC
6
+ swaps.rb: Display current eod swaps.
7
+ > USAGE: swaps.rb <contract> [json]
8
+ > contract a contract known to the system
9
+ > json switch to toggle json output instead of human readable
10
+ HEREDOC
11
+ if ARGV.empty?
12
+ puts HELP
13
+ exit
14
+ end
15
+
16
+
17
+ contract = ARGV[0].nil? ? nil : ARGV[0].upcase
18
+ json = ARGV.include? 'json'
19
+
20
+ sym = Cotcube::Helpers.get_id_set(contract: contract) rescue "ERROR: Could not determine contract '#{contract}'."
21
+
22
+ if sym.is_a? String; puts sym; puts HELP; exit 1; end
23
+
24
+ swaps = Cotcube::Level::load_swaps(interval: :daily, swap_type: :full, contract: contract, quiet: true).
25
+ select{|swap| not(swap[:empty]) and
26
+ not(swap[:ignored]) and
27
+ not(swap[:exceeded].presence ? (swap[:exceeded] < DateTime.now - 2.days) : false)
28
+ }
29
+ stencil = Cotcube::Level::EOD_Stencil.new( interval: :daily, swap_type: :full)
30
+ swaps.map!{|swap| stencil.use with: swap, sym: sym}
31
+ if json
32
+ puts swaps.to_json
33
+ else
34
+ puts '<none>' if swaps.empty?
35
+ swaps.each {|swap|
36
+ notice = if swap[:exceeded]
37
+ "EXCEEDED #{swap[:exceeded].strftime('%Y-%m-%d')}"
38
+ elsif swap[:ignored]
39
+ 'IGNORED'
40
+ else
41
+ "Current: #{format sym[:format], swap[:current_value]}"
42
+ end
43
+ Cotcube::Level.puts_swap(swap, format: sym[:format], notice: notice)
44
+ }
45
+ end
@@ -13,7 +13,7 @@ module Cotcube
13
13
  #
14
14
  # Current daily stencils contain dates from 2020-01-01 to 2023-12-31
15
15
  #
16
- def self.provide_raw_stencil(type:, interval: :daily, version: nil)
16
+ def self.provide_raw_stencil(type:, interval: :daily, version: nil, timezone: Cotcube::Helpers::CHICAGO)
17
17
  loading = lambda do |typ|
18
18
  file_base = "/var/cotcube/level/stencils/stencil_#{interval.to_s}_#{typ.to_s}.csv_"
19
19
  if Dir["#{file_base}?*"].empty?
@@ -27,7 +27,7 @@ module Cotcube
27
27
  raise ArgumentError, "Cannot open stencil from non-existant file #{file}."
28
28
  end
29
29
  end
30
- CSV.read(file).map{|x| { datetime: CHICAGO.parse(x.first).freeze, x: x.last.to_i.freeze } }
30
+ CSV.read(file).map{|x| { datetime: timezone.parse(x.first).freeze, x: x.last.to_i.freeze } }
31
31
  end
32
32
  unless const_defined? :RAW_STENCILS
33
33
  const_set :RAW_STENCILS, { daily:
@@ -80,7 +80,7 @@ module Cotcube
80
80
  raise ArgumentError, "Each stencil members should contain at least :datetime and :x" unless stencil.nil? or
81
81
  stencil.map{|x| ([:datetime, :x] - x.keys).empty? and [ActiveSupport::TimeWithZone, Day].include?( x[:datetime] ) and x[:x].is_a?(Integer)}.reduce(:&)
82
82
 
83
- base = stencil || EOD_Stencil.provide_raw_stencil(type: stencil_type, interval: :daily, version: version)
83
+ base = stencil || EOD_Stencil.provide_raw_stencil(type: stencil_type, interval: :daily, version: version, timezone: timezone)
84
84
 
85
85
  # fast rewind to previous trading day
86
86
  date = timezone.parse(date) unless [NilClass, Date, ActiveSupport::TimeWithZone].include? date.class
@@ -111,7 +111,12 @@ module Cotcube
111
111
  end
112
112
 
113
113
  def zero
114
- @zero ||= @base.find{|b| b[:x].zero? }
114
+ index(0)
115
+ end
116
+
117
+ def index(offset = 0)
118
+ @index ||= @base.index{|b| b[:x].zero? }
119
+ @base[@index + offset]
115
120
  end
116
121
 
117
122
  def apply(to: )
@@ -136,7 +141,7 @@ module Cotcube
136
141
  to.reject!{|x| x[:x].nil? }
137
142
  end
138
143
 
139
- def use(with:, sym:, zero:, grace: -2)
144
+ def use(with:, sym:, zero: nil, grace: -2)
140
145
  # todo: validate with (check if vslid swap
141
146
  # sym (check keys)
142
147
  # zero (ohlc with x.zero?)
@@ -147,14 +152,16 @@ module Cotcube
147
152
  start = base.find{|x| swap[:datetime] == x[:datetime]}
148
153
  swap[:current_change] = (swap[:tpi] * start[:x]).round(8)
149
154
  swap[:current_value] = swap[:members].last[ ohlc ] + swap[:current_change] * sym[:ticksize]
150
- swap[:current_diff] = (swap[:current_value] - zero[ohlc]) * (high ? 1 : -1 )
151
- swap[:current_dist] = (swap[:current_diff] / sym[:ticksize]).to_i
152
- swap[:exceeded] = zero[:datetime] if swap[:current_dist] < grace
155
+ unless zero.nil?
156
+ swap[:current_diff] = (swap[:current_value] - zero[ohlc]) * (high ? 1 : -1 )
157
+ swap[:current_dist] = (swap[:current_diff] / sym[:ticksize]).to_i
158
+ swap[:exceeded] = zero[:datetime] if swap[:current_dist] < grace
159
+ end
153
160
  swap
154
161
  end
155
- end
162
+ end
156
163
 
157
- end
164
+ end
158
165
 
159
166
  end
160
167
 
@@ -23,7 +23,7 @@ module Cotcube
23
23
 
24
24
  # human readable output
25
25
  # please note the format must be given, that should be taken from :sym
26
- def member_to_human(member,side: ,format:, daily: false)
26
+ def member_to_human(member,side: ,format:, daily: false, tws: false)
27
27
  high = (side == :upper)
28
28
  "#{ member[:datetime].strftime("%a, %Y-%m-%d#{daily ? "" :" %I:%M%p"}")
29
29
  } x: #{format '%-4d', member[:x]
@@ -40,33 +40,74 @@ module Cotcube
40
40
  # format: e.g. sym[:format]
41
41
  # short: print one line / less verbose
42
42
  # notice: add this to output as well
43
- def puts_swap(swap, format: , short: true, notice: nil, hash: 3)
44
- return if swap[:empty]
43
+ def puts_swap(swap, format: , short: true, notice: nil, hash: 3, tws: false)
44
+ return '' if swap[:empty]
45
+
46
+ # if presenting swaps from json, the datetimes need to be parsed first
47
+ swap[:datetime] = DateTime.parse(swap[:datetime]) if swap[:datetime].is_a? String
48
+ swap[:exceeded] = DateTime.parse(swap[:exceeded]) if swap[:exceeded].is_a? String
49
+ swap[:ignored] = DateTime.parse(swap[:ignored]) if swap[:ignored ].is_a? String
50
+ swap[:side] = swap[:side].to_sym
51
+ swap[:members].each do |mem|
52
+ mem[:datetime] = DateTime.parse(mem[:datetime]) if mem[:datetime].is_a? String
53
+ end
54
+
55
+ # TODO: create config-entry to contain 1.hour -- set of contracts ; 7.hours -- set of contracts [...]
56
+ # instead of hard-coding in here
57
+ # TODO: add also to :member_to_human
58
+ # then commit
59
+ if tws
60
+ case swap[:contract][0...2]
61
+ when *%w[ GC SI PL PA HG NG CL HO RB ]
62
+ delta_datetime = 1.hour
63
+ when *%w[ GG DX ]
64
+ delta_datetime = 7.hours
65
+ else
66
+ delta_datetime = 0
67
+ end
68
+ else
69
+ delta_datetime = 0
70
+ end
45
71
  daily = %i[ continuous daily ].include?(swap[:interval].to_sym) rescue false
46
72
  datetime_format = daily ? '%Y-%m-%d' : '%Y-%m-%d %I:%M %p'
47
73
  high = swap[:side] == :high
48
74
  ohlc = high ? :high : :low
49
75
  if notice.nil? and swap[:exceeded]
50
- notice = "exceeded #{swap[:exceeded].strftime(datetime_format)}"
76
+ notice = "exceeded #{(swap[:exceeded] + delta_datetime).strftime(datetime_format)}"
77
+ end
78
+ if swap[:ignored]
79
+ notice += " IGNORED"
51
80
  end
52
81
  if short
53
- puts (hash ? "#{swap[:digest][...hash]} ".colorize(:light_white) : '') +
54
- "S: #{swap[:side]
55
- } L: #{ format '%4d', swap[:length]
56
- } R: #{ format '%4d', swap[:rating]
57
- } D: #{ format '%4d', swap[:depth]
58
- } P: #{ format '%10s', (format '%5.2f', swap[:ppi])
59
- } F: #{ format format, swap[:members].last[ ohlc ]
60
- } S: #{ swap[:members].first[:datetime].strftime(datetime_format)
61
- } - #{ swap[:members].last[:datetime].strftime(datetime_format)
62
- }#{" NOTE: #{notice}" unless notice.nil?}".colorize(swap[:color] || :white )
82
+ res ="#{format '%7s', swap[:digest][...hash]
83
+ } #{ swap[:contract]
84
+ } #{ swap[:side].to_s
85
+ }".colorize( swap[:side] == :upper ? :light_green : :light_red ) +
86
+ " (#{ format '%4d', swap[:length]
87
+ },#{ format '%4d', swap[:rating]
88
+ },#{ format '%4d', swap[:depth]
89
+ }) P: #{ format '%6s', (format '%4.2f', swap[:ppi])
90
+ } #{
91
+ if swap[:current_value].nil?
92
+ "I: #{ format '%8s', (format format, swap[:members].last[ ohlc ]) }"
93
+ else
94
+ "C: #{ format '%8s', (format format, swap[:current_value]) } "
95
+ end
96
+ } [#{ (swap[:members].first[:datetime] + delta_datetime).strftime(datetime_format)
97
+ } - #{ (swap[:members].last[:datetime] + delta_datetime).strftime(datetime_format)
98
+ }]#{" NOTE: #{notice}" unless notice.nil?
99
+ }".colorize(swap[:color] || :white )
100
+ puts res
63
101
  else
64
- puts "side: #{swap[:side] }\tlen: #{swap[:length]} \trating: #{swap[:rating]}".colorize(swap[:color] || :white )
65
- puts "diff: #{swap[:ticks]}\tdif: #{swap[:diff].round(7)}\tdepth: #{swap[:depth]}".colorize(swap[:color] || :white )
66
- puts "tpi: #{swap[:tpi] }\tppi: #{swap[:ppi]}".colorize(swap[:color] || :white )
67
- puts "NOTE: #{notice}".colorize(:light_white) unless notice.nil?
68
- swap[:members].each {|x| puts member_to_human(x, side: swap[:side], format: format, daily: daily) }
102
+ res = ["side: #{swap[:side] }\tlen: #{swap[:length]} \trating: #{swap[:rating]}".colorize(swap[:color] || :white )]
103
+ res << "diff: #{swap[:ticks]}\tdif: #{swap[:diff].round(7)}\tdepth: #{swap[:depth]}".colorize(swap[:color] || :white )
104
+ res << "tpi: #{swap[:tpi] }\tppi: #{swap[:ppi]}".colorize(swap[:color] || :white )
105
+ res << "NOTE: #{notice}".colorize(:light_white) unless notice.nil?
106
+ swap[:members].each {|x| res << member_to_human(x, side: swap[:side], format: format, daily: daily) }
107
+ res = res.join("\n")
108
+ puts res
69
109
  end
110
+ res
70
111
  end
71
112
 
72
113
  # create a standardized name for the cache files
@@ -81,7 +122,9 @@ module Cotcube
81
122
  `mkdir -p #{dir}` unless File.exist?(dir)
82
123
  `ln -s #{dir} #{symlink}` unless File.exist?(symlink)
83
124
  file = "#{dir}/#{contract}_#{interval.to_s}_#{swap_type.to_s}.jsonl"
84
- `touch #{file}`
125
+ unless File.exist? file
126
+ `touch #{file}`
127
+ end
85
128
  file
86
129
  end
87
130
 
@@ -117,7 +160,9 @@ module Cotcube
117
160
 
118
161
  # loading of swaps is also straight forward
119
162
  # it takes few more efforts to normalize the values to their expected format
120
- def load_swaps(interval:, swap_type:, contract:, sym: nil, datetime: nil, recent: false, digest: nil, quiet: false, exceed: false)
163
+ #
164
+ # it is not too nice that some actual interactive process is done here in the load section
165
+ def load_swaps(interval:, swap_type:, contract:, sym: nil, datetime: nil, recent: false, digest: nil, quiet: false, exceed: false, keep_ignored: false)
121
166
  file = get_jsonl_name(interval: interval, swap_type: swap_type, contract: contract, sym: sym)
122
167
  jsonl = File.read(file)
123
168
  data = jsonl.
@@ -128,12 +173,13 @@ module Cotcube
128
173
  tap do |sw|
129
174
  sw[:datetime] = DateTime.parse(sw[:datetime]) rescue nil
130
175
  (sw[:exceeded] = DateTime.parse(sw[:exceeded]) rescue nil) if sw[:exceeded]
176
+ (sw[:ignored] = DateTime.parse(sw[:ignored]) rescue nil) if sw[:ignored]
131
177
  sw[:interval] = interval
132
178
  sw[:swap_type] = swap_type
133
179
  sw[:contract] = contract
134
180
  %i[ side ].each {|key| sw[key] = sw[key].to_sym rescue false }
135
- unless sw[:empty] or sw[:exceeded]
136
- sw[:color] = sw[:color].to_sym
181
+ unless sw[:empty] or sw[:exceeded] or sw[:ignored]
182
+ sw[:color] = sw[:color].to_sym
137
183
  sw[:members].map{|mem| mem[:datetime] = DateTime.parse(mem[:datetime]) }
138
184
  end
139
185
  end
@@ -144,13 +190,20 @@ module Cotcube
144
190
  raise RuntimeError, "Inconsistent history for '#{exc}'. Origin not found." if swap.nil?
145
191
  swap[:exceeded] = exc[:exceeded]
146
192
  end
193
+ # assign ignorance data to actual swaps
194
+ data.select{|swap| swap[:ignored] }.each do |ign|
195
+ swap = data.find{|ref| ref[:digest] == ign[:ref]}
196
+ raise RuntimeError, "Inconsistent history for '#{ign}'. Origin not found." if swap.nil?
197
+ swap[:ignored] = ign[:ignored]
198
+ end
147
199
  # do not return bare exceedance information
148
- data.reject!{|swap| swap[:exceeded] and swap[:members].nil? }
200
+ data.reject!{|swap| (swap[:ignored] or swap[:exceeded]) and swap[:members].nil? }
149
201
  # do not return swaps that are found 'later'
150
202
  data.reject!{|swap| swap[:datetime] > datetime } unless datetime.nil?
151
203
  # do not return exceeded swaps, that are exceeded in the past
152
204
  recent = 7.days if recent.is_a? TrueClass
153
205
  recent += 5.hours if recent
206
+ data.reject!{|swap| swap[:ignored] } unless keep_ignored
154
207
  data.reject!{|swap| swap[:exceeded] and swap[:exceeded] < datetime - (recent ? recent : 0) } unless datetime.nil?
155
208
  # remove exceedance information that is found 'later'
156
209
  data.map{|swap| swap.delete(:exceeded) if swap[:exceeded] and swap[:exceeded] > datetime} unless datetime.nil?
@@ -202,20 +255,31 @@ module Cotcube
202
255
  save_swaps to_save, interval: swap[:interval], swap_type: swap[:swap_type], contract: contract, sym: sym, quiet: (not debug)
203
256
  swap[:exceeded] = update[:exceeded]
204
257
  end
205
- %i[ current_change current_value current_diff current_dist ].map{|key| swap[key] = update[key] }
258
+ %i[ current_change current_value current_diff current_dist alert].map{|key| swap[key] = update[key] }
206
259
  swap
207
260
  end.compact
208
261
  end
209
262
 
210
- def mark_exceeded(swap:, datetime:, debug: false)
263
+ def mark_exceeded(swap:, datetime:, debug: false, sym: nil)
211
264
  to_save = {
212
265
  datetime: datetime,
213
266
  ref: swap[:digest],
214
267
  side: swap[:side],
215
268
  exceeded: datetime
216
269
  }
217
- save_swaps to_save, interval: swap[:interval], swap_type: swap[:swap_type], sym: Cotcube::Helpers.get_id_set(contract: swap[:contract]), contract: swap[:contract], quiet: (not debug)
218
- swap[:exceeded] = datetime
270
+ sym ||= Cotcube::Helpers.get_id_set(contract: swap[:contract])
271
+ save_swaps to_save, interval: swap[:interval], swap_type: swap[:swap_type], sym: sym, contract: swap[:contract], quiet: (not debug)
272
+ swap
273
+ end
274
+
275
+ def mark_ignored(swap:, datetime: DateTime.now, sym: , debug: true)
276
+ to_save = {
277
+ datetime: datetime,
278
+ ref: swap[:digest],
279
+ side: swap[:side],
280
+ ignored: datetime
281
+ }
282
+ save_swaps to_save, interval: swap[:interval], swap_type: swap[:swap_type], sym: sym, contract: swap[:contract], quiet: (not debug)
219
283
  swap
220
284
  end
221
285
 
@@ -35,6 +35,7 @@ module Cotcube
35
35
  debug: false,
36
36
  weeks: 6,
37
37
  future: 2,
38
+ measuring: false,
38
39
  version: nil, # when referring to a specicic version of the stencil
39
40
  stencil: nil, # instead of preparing, use this one if set
40
41
  warnings: true # be more quiet
@@ -51,10 +52,22 @@ module Cotcube
51
52
  @datetime += interval while @datetime <= datetime - interval
52
53
  @datetime -= interval
53
54
 
54
- const = "RAW_INTRA_STENCIL_#{@shiftset[:nr]}_#{interval.in_minutes.to_i}".to_sym
55
+ now = DateTime.now
56
+ measure = lambda {|x| puts "\nMeasured #{(Time.now - now).to_f.round(2)}: ".colorize(:light_yellow) + x + "\n\n" if measuring }
57
+
58
+ measure.call "Starting initialization for asset '#{asset}' "
59
+
60
+ const = "RAW_INTRA_STENCIL_#{@shiftset[:nr]}_#{interval.in_minutes.to_i}_#{weeks}_#{future}".to_sym
61
+ cachefile = "/var/cotcube/level/stencils/cache/#{swap_type.to_s}_#{interval}_#{@datetime.strftime('%Y-%m-%d-%H-%M')}.json"
62
+
55
63
  if Object.const_defined? const
64
+ measure.call 'getting cached base from memory'
56
65
  @base = (Object.const_get const).map{|z| z.dup}
66
+ elsif File.exist? cachefile
67
+ measure.call 'getting cached base from file'
68
+ @base = JSON.parse(File.read(cachefile), symbolize_names: true).map{|z| z[:datetime] = DateTime.parse(z[:datetime]); z[:type] = z[:type].to_sym; z }
57
69
  else
70
+ measure.call 'creating base from shiftset'
58
71
  start_time = lambda {|x| @shiftset[x].split('-').first rescue '' }
59
72
  start_hours = lambda {|x| @shiftset[x].split('-').first[ 0.. 1].to_i.send(:hours) rescue 0 }
60
73
  start_minutes = lambda {|x| @shiftset[x].split('-').first[-2..-1].to_i.send(:minutes) rescue 0 }
@@ -62,7 +75,7 @@ module Cotcube
62
75
  end_hours = lambda {|x| @shiftset[x].split('-').last [ 0.. 1].to_i.send(:hours) rescue 0 }
63
76
  end_minutes = lambda {|x| @shiftset[x].split('-').last [-2..-1].to_i.send(:minutes) rescue 0 }
64
77
 
65
- runner = (@datetime -
78
+ runner = (@datetime -
66
79
  weeks * 7.days).beginning_of_week(:sunday)
67
80
  tm_runner = lambda { runner.strftime('%H%M') }
68
81
  @base = []
@@ -113,7 +126,9 @@ module Cotcube
113
126
  end
114
127
  end
115
128
  Object.const_set(const, @base.map{|z| z.dup})
129
+ File.open(cachefile, 'w'){|f| f.write(@base.to_json)}
116
130
  end
131
+ measure.call "base created with #{@base.size} records"
117
132
 
118
133
  case swap_type
119
134
  when :full
@@ -131,42 +146,44 @@ module Cotcube
131
146
  else
132
147
  raise ArgumentError, "Unknown stencil/swap type '#{swap_type}'"
133
148
  end
149
+ measure.call "swaptype #{swap_type} applied"
134
150
  @base.map!{|z| z.dup}
151
+ measure.call 'base dupe\'d'
135
152
 
136
153
  # zero is, were either x[:datetime] == @datetime (when we are intraday)
137
154
  # or otherwise {x[:datetime] <= @datetime}.last (when on maintenance)
138
- @index = @base.index{|x| x == @base.select{|y| y[:datetime] <= @datetime }.last }
155
+ selector = @base.select{|y| y[:datetime] <= @datetime }.last
156
+ @index = @base.index{|x| x == selector }
157
+ measure.call 'index selected'
139
158
  @index -= 1 while %i[sow sod mpre mpost eod eow].include? @base[@index][:type]
159
+ measure.call 'index adjusted'
140
160
  @datetime = @base[@index][:datetime]
141
161
  @zero = @base[@index]
142
162
  counter = 0
163
+ measure.call "Applying counter to past"
143
164
  while @base[@index - counter] and @index - counter >= 0
144
165
  @base[@index - counter][:x] = counter
145
166
  counter += 1
146
167
  end
147
168
  counter = 0
169
+ measure.call "Applying counter to future"
148
170
  while @base[@index + counter] and @index + counter < @base.length
149
171
  @base[@index + counter][:x] = -counter
150
172
  counter += 1
151
173
  end
174
+ measure.call 'initialization finished'
152
175
  end
153
176
 
154
- =begin
155
- def dup
156
- Intraday_Stencil.new(
157
- debug: @debug,
158
- interval: @interval,
159
- swap_type: @swap_type,
160
- datetime: @datetime,
161
- stencil: @base.map{|x| x.dup}
162
- )
163
- end
164
- =end
165
-
166
177
  def zero
167
178
  @zero ||= @base.find{|b| b[:x].zero? }
168
179
  end
169
180
 
181
+ def index(offset = 0)
182
+ @index ||= @base.index{|b| b[:x].zero? }
183
+ @base[@index + offset]
184
+ end
185
+
186
+
170
187
  def apply(to: )
171
188
  offset = 0
172
189
  @base.each_index do |i|
@@ -190,7 +207,7 @@ module Cotcube
190
207
  to.reject!{|x| x[:x].nil? }
191
208
  end
192
209
 
193
- def use(with:, sym:, zero:, grace: -2)
210
+ def use(with:, sym:, zero: nil, grace: -2)
194
211
  # todo: validate with (check if vslid swap
195
212
  # sym (check keys)
196
213
  # zero (ohlc with x.zero?)
@@ -201,9 +218,12 @@ module Cotcube
201
218
  start = base.find{|x| swap[:datetime] == x[:datetime]}
202
219
  swap[:current_change] = (swap[:tpi] * start[:x]).round(8)
203
220
  swap[:current_value] = swap[:members].last[ ohlc ] + swap[:current_change] * sym[:ticksize]
204
- swap[:current_diff] = (swap[:current_value] - zero[ohlc]) * (high ? 1 : -1 )
205
- swap[:current_dist] = (swap[:current_diff] / sym[:ticksize]).to_i
206
- swap[:exceeded] = zero[:datetime] if swap[:current_dist] < grace
221
+ unless zero.nil?
222
+ swap[:current_diff] = (swap[:current_value] - zero[ohlc]) * (high ? 1 : -1 )
223
+ swap[:current_dist] = (swap[:current_diff] / sym[:ticksize]).to_i
224
+ swap[:alert] = (swap[:current_diff] / zero[:atr5]).round(2)
225
+ swap[:exceeded] = zero[:datetime] if swap[:current_dist] < grace
226
+ end
207
227
  swap
208
228
  end
209
229
  end
data/lib/cotcube-level.rb CHANGED
@@ -40,6 +40,8 @@ module Cotcube
40
40
  :get_jsonl_name,
41
41
  :load_swaps,
42
42
  :check_exceedance,
43
+ :mark_exceeded,
44
+ :mark_ignored,
43
45
  :member_to_human
44
46
 
45
47
  # please note that module_functions of sources provided in non-public files must slso be published within these
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.3.4.1
4
+ version: 0.3.4.2
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-10-09 00:00:00.000000000 Z
11
+ date: 2021-12-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -120,6 +120,8 @@ files:
120
120
  - Gemfile
121
121
  - README.md
122
122
  - VERSION
123
+ - bin/iswaps.rb
124
+ - bin/swaps.rb
123
125
  - cotcube-level.gemspec
124
126
  - lib/cotcube-level.rb
125
127
  - lib/cotcube-level/detect_slope.rb
@@ -149,7 +151,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
149
151
  - !ruby/object:Gem::Version
150
152
  version: '0'
151
153
  requirements: []
152
- rubygems_version: 3.1.2
154
+ rubygems_version: 3.1.6
153
155
  signing_key:
154
156
  specification_version: 4
155
157
  summary: A gem to shear a time series