cotcube-level 0.3.3 → 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 +5 -0
- data/VERSION +1 -1
- data/lib/cotcube-level/helpers.rb +7 -5
- data/lib/cotcube-level/intraday_stencil.rb +101 -67
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '04184473172dd9ffd09c49a16bf6c2a724eb5cbef3f0f3d5423c44dea55f530f'
|
4
|
+
data.tar.gz: 75d1363041e3767a2f79c277a0d945fd830c1521df481194d8162c36b36044f2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70875d4dd83cb114b62456866b7c8ddaaa9753890442b06d71d770bb6408994cadcf3a5cd12704d658e049ed2aba0cd14bdbf79ce9d25e462ff9453c785a5142
|
7
|
+
data.tar.gz: 34aa4547dab7a3b13c896db860bcb23d36c432a0c3480cadf2e8a542351316d92cbe10a321ff8b20da236556312da27e8bb53ac6f65a1d885b48ccbe270c41ef
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
## 0.3.4 (October 06, 2021)
|
2
|
+
- intraday_stencil: major rework resp. rebuild ... now beta-ready
|
3
|
+
- helpers: preparing puts_swap and get_jsonl_name to work intraday
|
4
|
+
- puts_swap: changed output scheme to provide exceedance as NOTE
|
5
|
+
|
1
6
|
## 0.3.3 (October 05, 2021)
|
2
7
|
- helpers::load_swaps: added :exceed to allow 1(sic) swap to be exceeded while loading
|
3
8
|
- tritangulate: added :manual for feature of manual swap creation with base of 2 members
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.4
|
@@ -42,10 +42,13 @@ module Cotcube
|
|
42
42
|
# notice: add this to output as well
|
43
43
|
def puts_swap(swap, format: , short: true, notice: nil, hash: 3)
|
44
44
|
return if swap[:empty]
|
45
|
-
daily = %i[ continuous daily ].include?(swap[:interval].to_sym)
|
46
|
-
datetime_format = daily ? '%Y-%m-%d' : '%Y-%m-%d %
|
45
|
+
daily = %i[ continuous daily ].include?(swap[:interval].to_sym) rescue false
|
46
|
+
datetime_format = daily ? '%Y-%m-%d' : '%Y-%m-%d %I:%M %p'
|
47
47
|
high = swap[:side] == :high
|
48
48
|
ohlc = high ? :high : :low
|
49
|
+
if notice.nil? and swap[:exceeded]
|
50
|
+
notice = "exceeded #{swap[:exceeded].strftime(datetime_format)}"
|
51
|
+
end
|
49
52
|
if short
|
50
53
|
puts (hash ? "#{swap[:digest][...hash]} ".colorize(:light_white) : '') +
|
51
54
|
"S: #{swap[:side]
|
@@ -56,8 +59,7 @@ module Cotcube
|
|
56
59
|
} F: #{ format format, swap[:members].last[ ohlc ]
|
57
60
|
} S: #{ swap[:members].first[:datetime].strftime(datetime_format)
|
58
61
|
} - #{ swap[:members].last[:datetime].strftime(datetime_format)
|
59
|
-
}#{
|
60
|
-
}#{" NOTE: #{notice}" unless notice.nil?}".colorize(swap[:color] || :white )
|
62
|
+
}#{" NOTE: #{notice}" unless notice.nil?}".colorize(swap[:color] || :white )
|
61
63
|
else
|
62
64
|
puts "side: #{swap[:side] }\tlen: #{swap[:length]} \trating: #{swap[:rating]}".colorize(swap[:color] || :white )
|
63
65
|
puts "diff: #{swap[:ticks]}\tdif: #{swap[:diff].round(7)}\tdepth: #{swap[:depth]}".colorize(swap[:color] || :white )
|
@@ -70,7 +72,7 @@ module Cotcube
|
|
70
72
|
# create a standardized name for the cache files
|
71
73
|
# and, on-the-fly, create these files plus their directory
|
72
74
|
def get_jsonl_name(interval:, swap_type:, contract:, sym: nil)
|
73
|
-
raise "Interval #{interval } is not supported, please choose from #{INTERVALS}" unless INTERVALS.include? interval
|
75
|
+
raise "Interval #{interval } is not supported, please choose from #{INTERVALS}" unless INTERVALS.include?(interval) || interval.is_a?(Integer)
|
74
76
|
raise "Swaptype #{swap_type} is not supported, please choose from #{SWAPTYPES}" unless SWAPTYPES.include? swap_type
|
75
77
|
sym ||= Cotcube::Helpers.get_id_set(contract: contract)
|
76
78
|
root = '/var/cotcube/level'
|
@@ -1,12 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Cotcube
|
2
4
|
module Level
|
3
|
-
|
5
|
+
|
4
6
|
class Intraday_Stencil
|
5
7
|
|
6
|
-
GLOBAL_SOW = { 'CT' => '0000-1700' }
|
7
|
-
GLOBAL_EOW = { 'CT' => '1700-0000' }
|
8
|
-
GLOBAL_EOD = { 'CT' => '1600-1700' }
|
9
8
|
|
9
|
+
# Class method that loads the (latest) shiftset for given asset
|
10
|
+
# These raw stencils are located in /var/cotcube/level/stencils/shiftsets.csv
|
11
|
+
#
|
10
12
|
|
11
13
|
def self.shiftset(asset:, sym: nil)
|
12
14
|
shiftset_file = '/var/cotcube/level/stencils/shiftsets.csv'
|
@@ -18,45 +20,53 @@ module Cotcube
|
|
18
20
|
sym ||= Cotcube::Helpers.get_id_set(symbol: asset)
|
19
21
|
current_set = shiftsets.find{|s| s[:symbols] =~ /#{sym[:type]}/ }
|
20
22
|
return current_set.tap{|s| headers.map{|h| s[h] = nil if s[h] == '---------' }; s[:rth5] ||= s[:rth]; s[:mpost5] ||= s[:mpost] } unless current_set.nil?
|
21
|
-
raise "Cannot get shiftset for #{sym[:type]}: #{asset}, please prepare #{shiftset_file} before!"
|
23
|
+
raise "Cannot get shiftset for #{sym[:type]}: #{asset}, please prepare #{shiftset_file} before!"
|
22
24
|
end
|
23
25
|
|
24
26
|
attr_reader :base, :shiftset, :timezone, :datetime, :zero, :index
|
25
27
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
28
|
+
|
29
|
+
|
30
|
+
def initialize(
|
31
|
+
asset:,
|
32
|
+
interval: 30.minutes,
|
33
|
+
swap_type: :full,
|
34
|
+
datetime: nil,
|
35
|
+
debug: false,
|
36
|
+
weeks: 6,
|
37
|
+
future: 2,
|
38
|
+
version: nil, # when referring to a specicic version of the stencil
|
39
|
+
stencil: nil, # instead of preparing, use this one if set
|
40
|
+
warnings: true # be more quiet
|
41
|
+
)
|
42
|
+
@shiftset = Intraday_Stencil.shiftset(asset: asset)
|
43
|
+
@timezone = Cotcube::Level::TIMEZONES[@shiftset[:tz]]
|
44
|
+
@debug = debug
|
45
|
+
@interval = interval
|
46
|
+
@swap_type = swap_type
|
47
|
+
@warnings = warnings
|
48
|
+
datetime ||= DateTime.now
|
37
49
|
datetime = @timezone.at(datetime.to_i) unless datetime.is_a? ActiveSupport::TimeWithZone
|
38
|
-
# slight flaw, as datetime does not carry the actuall timezone information but just the abbr. timezone name (like CDT or CEST)
|
39
|
-
raise "Zone mismatch: Timezone of asset is #{@timezone.now.zone} but datetime given is #{dateime.zone}" unless @timezone.now.zone == datetime.zone
|
40
50
|
@datetime = datetime.beginning_of_day
|
41
51
|
@datetime += interval while @datetime <= datetime - interval
|
42
|
-
@datetime -= interval
|
52
|
+
@datetime -= interval
|
53
|
+
|
43
54
|
const = "RAW_INTRA_STENCIL_#{@shiftset[:nr]}_#{interval.in_minutes.to_i}".to_sym
|
44
55
|
if Object.const_defined? const
|
45
56
|
@base = (Object.const_get const).map{|z| z.dup}
|
46
57
|
else
|
47
|
-
|
48
58
|
start_time = lambda {|x| @shiftset[x].split('-').first rescue '' }
|
49
59
|
start_hours = lambda {|x| @shiftset[x].split('-').first[ 0.. 1].to_i.send(:hours) rescue 0 }
|
50
60
|
start_minutes = lambda {|x| @shiftset[x].split('-').first[-2..-1].to_i.send(:minutes) rescue 0 }
|
51
61
|
end_time = lambda {|x| @shiftset[x].split('-').last rescue '' }
|
52
62
|
end_hours = lambda {|x| @shiftset[x].split('-').last [ 0.. 1].to_i.send(:hours) rescue 0 }
|
53
|
-
end_minutes = lambda {|x| @shiftset[x].split('-').last [-2..-1].to_i.send(:minutes) rescue 0 }
|
63
|
+
end_minutes = lambda {|x| @shiftset[x].split('-').last [-2..-1].to_i.send(:minutes) rescue 0 }
|
54
64
|
|
55
|
-
|
65
|
+
runner = (@datetime -
|
56
66
|
weeks * 7.days).beginning_of_week(:sunday)
|
57
67
|
tm_runner = lambda { runner.strftime('%H%M') }
|
58
|
-
@base = []
|
59
|
-
(weeks+future).times do
|
68
|
+
@base = []
|
69
|
+
(weeks+future).times do
|
60
70
|
while tm_runner.call < GLOBAL_SOW[@shiftset[:tz]].split('-').last
|
61
71
|
# if daylight is switched, this phase will be shorter or longer
|
62
72
|
@base << { datetime: runner, type: :sow }
|
@@ -81,10 +91,10 @@ module Cotcube
|
|
81
91
|
yet_rth = true
|
82
92
|
end
|
83
93
|
end
|
84
|
-
while ((sophase > eophase) ? (tm_runner.call >= sophase or tm_runner.call < eophase) : (tm_runner.call < eophase))
|
94
|
+
while ((sophase > eophase) ? (tm_runner.call >= sophase or tm_runner.call < eophase) : (tm_runner.call < eophase))
|
85
95
|
current = { datetime: runner, type: phase }
|
86
96
|
if phase == :rth and not yet_rth
|
87
|
-
current[:block] = true
|
97
|
+
current[:block] = true
|
88
98
|
yet_rth = true
|
89
99
|
end
|
90
100
|
@base << current
|
@@ -100,80 +110,104 @@ module Cotcube
|
|
100
110
|
while runner < end_of_week
|
101
111
|
@base << { datetime: runner, type: :eow }
|
102
112
|
runner += interval
|
103
|
-
end
|
113
|
+
end
|
104
114
|
end
|
105
115
|
Object.const_set(const, @base.map{|z| z.dup})
|
106
116
|
end
|
107
|
-
|
108
|
-
|
109
|
-
|
117
|
+
|
118
|
+
case swap_type
|
119
|
+
when :full
|
120
|
+
@base.select!{|x| %i[ pre rth post ].include?(x[:type]) }
|
121
|
+
when :rth
|
122
|
+
@base.select!{|x| x[:type] == :rth }
|
123
|
+
# to.map{ |x| [:high, :low, :volume].map{|z| x[z] = nil} if x[:block] }
|
124
|
+
when :flow
|
125
|
+
@base.reject!{|x| %i[ meow postmm postmm5 ].include?(x[:type]) }
|
126
|
+
@base.
|
127
|
+
map{ |x|
|
128
|
+
[:high, :low, :volume].map{|z| x[z] = nil} unless x[:type] == :rth
|
129
|
+
# [:high, :low, :volume].map{|z| x[z] = nil} if x[:block]
|
130
|
+
}
|
131
|
+
when :run
|
132
|
+
@base.select!{|x| %i[ premarket rth postmarket ].include? x[:type]}
|
133
|
+
else
|
134
|
+
raise ArgumentError, "Unknown stencil/swap type '#{type}'"
|
135
|
+
end
|
136
|
+
@base.map!{|z| z.dup}
|
137
|
+
|
138
|
+
@index = @base.index{|x| x[:datetime] == @datetime }
|
139
|
+
@index -= 1 while %i[sow sod mpre mpost eod eow].include? @base[@index][:type]
|
110
140
|
@datetime = @base[@index][:datetime]
|
111
141
|
@zero = @base[@index]
|
112
|
-
counter = 0
|
142
|
+
counter = 0
|
113
143
|
while @base[@index - counter] and @index - counter >= 0
|
114
144
|
@base[@index - counter][:x] = counter
|
115
145
|
counter += 1
|
116
146
|
end
|
117
|
-
counter = 0
|
147
|
+
counter = 0
|
118
148
|
while @base[@index + counter] and @index + counter < @base.length
|
119
149
|
@base[@index + counter][:x] = -counter
|
120
150
|
counter += 1
|
121
151
|
end
|
122
|
-
@base.select!{|z| z[:x] <= 0 or z[:high]}
|
123
152
|
end
|
124
153
|
|
125
|
-
|
126
|
-
|
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
|
+
def zero
|
167
|
+
@zero ||= @base.find{|b| b[:x].zero? }
|
127
168
|
end
|
128
169
|
|
129
|
-
|
130
|
-
def apply(to:, type:, force: false, debug: false)
|
170
|
+
def apply(to: )
|
131
171
|
offset = 0
|
132
|
-
|
172
|
+
@base.each_index do |i|
|
133
173
|
begin
|
134
|
-
offset += 1 while
|
135
|
-
puts "#{i}\t#{offset}\t#{@base[i+offset][:datetime]} < #{to[i][:datetime]}" if debug
|
174
|
+
offset += 1 while to[i+offset][:datetime] < @base[i][:datetime]
|
136
175
|
rescue
|
137
176
|
# appending
|
138
|
-
|
139
|
-
@base << to[i]
|
177
|
+
to << @base[i]
|
140
178
|
next
|
141
179
|
end
|
142
|
-
if
|
180
|
+
if to[i+offset][:datetime] > @base[i][:datetime]
|
143
181
|
# skipping
|
144
|
-
puts "skipping #{i}\t#{offset}\t#{@base[i+offset][:datetime]} < #{to[i][:datetime]}" if debug
|
145
182
|
offset -= 1
|
146
183
|
next
|
147
184
|
end
|
148
185
|
# merging
|
149
|
-
|
150
|
-
|
151
|
-
puts "MERGED:\t#{i}\t#{offset}\t#{@base[j]}" if debug
|
186
|
+
to[i+offset][:x] = @base[i][:x]
|
187
|
+
to[i+offset][:type] = @base[i][:type]
|
152
188
|
end
|
153
189
|
# finally remove all bars that do not belong to the stencil (i.e. holidays)
|
154
|
-
|
155
|
-
when :full
|
156
|
-
@base.select!{|x| %i[ pre rth post ].include?(x[:type]) }
|
157
|
-
when :rth
|
158
|
-
@base.select!{|x| x[:type] == :rth }
|
159
|
-
# to.map{ |x| [:high, :low, :volume].map{|z| x[z] = nil} if x[:block] }
|
160
|
-
when :flow
|
161
|
-
@base.reject!{|x| %i[ meow postmm postmm5 ].include?(x[:type]) }
|
162
|
-
@base.
|
163
|
-
map{ |x|
|
164
|
-
[:high, :low, :volume].map{|z| x[z] = nil} unless x[:type] == :rth
|
165
|
-
# [:high, :low, :volume].map{|z| x[z] = nil} if x[:block]
|
166
|
-
}
|
167
|
-
when :run
|
168
|
-
@base.select!{|x| %i[ premarket rth postmarket ].include? x[:type]}
|
169
|
-
else
|
170
|
-
raise ArgumentError, "Unknown stencil/swap type '#{type}'"
|
171
|
-
end
|
172
|
-
@base.map!{|z| z.dup}
|
190
|
+
to.reject!{|x| x[:x].nil? }
|
173
191
|
end
|
174
192
|
|
193
|
+
def use(with:, sym:, zero:, grace: -2)
|
194
|
+
# todo: validate with (check if vslid swap
|
195
|
+
# sym (check keys)
|
196
|
+
# zero (ohlc with x.zero?)
|
197
|
+
# side ( upper or lower)
|
198
|
+
swap = with.dup
|
199
|
+
high = swap[:side] == :upper
|
200
|
+
ohlc = high ? :high : :low
|
201
|
+
start = base.find{|x| swap[:datetime] == x[:datetime]}
|
202
|
+
swap[:current_change] = (swap[:tpi] * start[:x]).round(8)
|
203
|
+
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
|
207
|
+
swap
|
208
|
+
end
|
175
209
|
end
|
176
210
|
|
177
|
-
Intraday_Stencils = Intraday_Stencil
|
178
211
|
end
|
212
|
+
|
179
213
|
end
|
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
|
+
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-10-
|
11
|
+
date: 2021-10-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|