cotcube-level 0.3.4.1 → 0.3.4.2

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: 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