lib/cotcube-bardata/daily.rb in cotcube-bardata-0.1.15.6 vs lib/cotcube-bardata/daily.rb in cotcube-bardata-0.1.16
- old
+ new
@@ -144,21 +144,17 @@
data += eods.reverse
end
measuring.call("Finished retrieving dailies.")
result = []
- rounding = 8 # sym[:format].split('.').last.to_i rescue 6
+ rounding = 8
indicators ||= {
- typical: Cotcube::Indicators.calc(a: :high, b: :low, c: :close) {|high, low, close| (high + low + close) / 3 },
- sma250_high: Cotcube::Indicators.sma(key: :high, length: 250),
- sma250_low: Cotcube::Indicators.sma(key: :low, length: 250),
- sma250_typ: Cotcube::Indicators.sma(key: :typical, length: 250),
- dist: Cotcube::Indicators.calc(a: :high, b: :low, finalize: :to_i) {|high, low| ((high-low) / ticksize) },
+ tr: Cotcube::Indicators.true_range,
+ atr5: Cotcube::Indicators.ema(key: :tr, length: 5),
+ dist: Cotcube::Indicators.calc(a: :high, b: :low, finalize: :to_i) {|high, low| ((high-low) / ticksize) }
}
-
-
data.group_by { |x| x[:date] }.map do |k, v|
v.map { |x| x.delete(:date) }
avg_bar = {
date: k,
contract: v.max_by{|x| x[:oi] }[:contract],
@@ -178,13 +174,13 @@
print format('%12s: ', k.to_s) if debug
tmp = v.call(avg_bar)
avg_bar[k] = tmp.respond_to?(:round) ? tmp.round(rounding) : tmp
puts avg_bar[k] if debug
end
- %i[tr atr5].each { |ind|
- avg_bar[ind] = (avg_bar[ind] / sym[:ticksize]).round.to_i unless avg_bar[ind].nil?
- }
+ #%i[tr atr5].each { |ind|
+ # avg_bar[ind] = (avg_bar[ind] / sym[:ticksize]).round.to_i unless avg_bar[ind].nil?
+ #}
result << avg_bar
result.last[:contracts] = v
end
result
end
@@ -205,48 +201,50 @@
ema_low_n = "ema#{ema_length}_low".to_sym
ema_filter = "ema#{ema_length}_filter".to_sym
indicators = {
ema_high_n => Cotcube::Indicators.ema(key: :high, length: ema_length, smoothing: 2),
ema_low_n => Cotcube::Indicators.ema(key: :low, length: ema_length, smoothing: 2),
+ # NOTE: TR / ATR5 are in default set of continuous
:tr => Cotcube::Indicators.true_range,
:atr5 => Cotcube::Indicators.ema(key: :tr, length: 5, smoothing: 2),
ema_filter => Cotcube::Indicators.calc(a: :high, b: :low, c: :close,
d: ema_high_n, e: ema_low_n, f: :atr5,
finalize: :to_i) do |high, low, close, ema_high, ema_low, atr5|
- if close > ema_high and (low - ema_high).abs <= atr5 / 5.0; 3 # :bullish_tipped
- elsif low > ema_high and (low - ema_high).abs >= atr5 * 3.0; 5 # :bullish_away
- elsif low > ema_high and (low - ema_high).abs <= atr5 / 1.5; 2 # :bullish_nearby
- elsif low > ema_high; 4 # :bullish
+ if close > ema_high and (low - ema_high).abs <= atr5 / 5.0; 3 # :bullish_tipped
+ elsif low > ema_high and (low - ema_high).abs >= atr5 * 3.0; 5 # :bullish_away
+ elsif low > ema_high and (low - ema_high).abs <= atr5 / 1.5; 2 # :bullish_nearby
+ elsif low > ema_high; 4 # :bullish
- elsif close < ema_low and (high - ema_low).abs <= atr5 / 5.0; -3 # :bearish_tipped
- elsif high < ema_low and (high - ema_low).abs >= atr5 * 3.0; -5 # :bearish_away
- elsif high < ema_low and (high - ema_low).abs <= atr5 / 1.5; -2 # :bearish_nearby
- elsif high < ema_low; -4 # :bearish
+ elsif close < ema_low and (high - ema_low).abs <= atr5 / 5.0; -3 # :bearish_tipped
+ elsif high < ema_low and (high - ema_low).abs >= atr5 * 3.0; -5 # :bearish_away
+ elsif high < ema_low and (high - ema_low).abs <= atr5 / 1.5; -2 # :bearish_nearby
+ elsif high < ema_low; -4 # :bearish
- elsif close >= ema_high and (close - ema_high).abs > atr5 ; 2 # :bullish_closed
- elsif close <= ema_low and (close - ema_low ).abs > atr5 ; -2 # :bearish_closed
- elsif close >= ema_high; 1 # :bullish_weak
- elsif close <= ema_low; -1 # :bearish_weak
- elsif close > ema_low and close < ema_high; 0 # :ambigue
- else
- raise RuntimeError, "Unconsidered Indicator value with #{high}, #{low}, #{close}, #{ema_high}, #{ema_low}, #{atr5}"
+ elsif close >= ema_high and (close - ema_high).abs > atr5 ; 2 # :bullish_closed
+ elsif close <= ema_low and (close - ema_low ).abs > atr5 ; -2 # :bearish_closed
+ elsif close >= ema_high; 1 # :bullish_weak
+ elsif close <= ema_low; -1 # :bearish_weak
+ elsif close > ema_low and close < ema_high; 0 # :ambigue
+ else
+ raise RuntimeError, "Unconsidered Indicator value with #{high}, #{low}, #{close}, #{ema_high}, #{ema_low}, #{atr5}"
- end
- end
+ end
+ end
}
filter = Cotcube::Bardata.continuous(symbol: symbol, indicators: indicators).
map{ |z| z[:datetime] = DateTime.parse(z[:date]); z[:datetime] += z[:datetime].wday == 5 ? 3 : 1; z.slice(:datetime, ema_filter) }.
group_by{ |z| z[:datetime] }.
map{ |k,v| [ k, v[0][ema_filter] ] }.
to_h.
- tap{ |z| z.to_a[print_range].each { |v|
- puts "#{v[0].strftime('%Y-%m-%d')
- } : #{format '%2d', v[1]
- }".colorize(v[1] > 3 ? :light_green : v[1] > 1 ? :green : v[1] < -3 ? :light_red : v[1] < -1 ? :red : :white )
- } if print_range.is_a? Range
- }
+ tap{ |z|
+ z.to_a[print_range].each { |v|
+ puts "#{symbol} #{v[0].strftime('%Y-%m-%d')
+ } #{format '%2d', v[1]
+ }".colorize(v[1] > 3 ? :light_green : v[1] > 1 ? :green : v[1] < -3 ? :light_red : v[1] < -1 ? :red : :white )
+ } if print_range.is_a? Range
+ }
end
def continuous_ml(symbol: nil, id: nil, base: nil)
(base.nil? ? Cotcube::Bardata.continuous(symbol: symbol, id: id) : base).map do |x|
x[:ml] = x[:contracts].max_by { |z| z[:volume] }[:contract]
@@ -368,24 +366,43 @@
ytoday = date.yday
data = continuous_overview(id: id, selector: selector, filter: filter, human: false, config: init, measure: measure)
.reject { |k, _| k[-2..].to_i >= date.year % 2000 }
.group_by { |k, _| k[2] }
measuring.call("Retrieved continous_overview")
- output_sent = []
- early_year=nil
long_output = []
+
+ toydate = -> (z,y=2021) { str = "#{z>365 ? y+1 : y} #{z>365 ? z-365 : z}"; DateTime.strptime(str, '%Y %j').strftime('%Y-%m-%d') }
+
data.keys.sort.each do |month|
puts "Processing #{sym[:symbol]}#{month}" if debuglevel > 1
v0 = data[month]
+
# ldays is the list of 'last days'
ldays = v0.map { |_, v1| Date.parse(v1.last[:date]).yday }
# fdays is the list of 'first days'
fdays = v0.map { |_, v1| Date.parse(v1.first[:date]).yday }.sort
# if the last ml day nears the end of the year, we must fix
ldays.map! { |x| x > 350 ? x - 366 : x } if ldays.min < 50
fday = fdays[fdays.size / 2]
lavg = ldays.reduce(:+) / ldays.size
+
+ # rubocop:disable Layout/ClosingParenthesisIndentation
+ current = {
+ month: month,
+ contract: "#{sym[:symbol]}#{month}",
+ first_ml: fday,
+ last_min: ldays.min,
+ last_avg: lavg,
+ last_max: ldays.max,
+ until_start: fday - ytoday,
+ until_end: ldays.min - ytoday
+ }
+ current[:until_end] += 365 if current[:until_end] - current[:until_start] < 0
+ current[:until_end] -= 365 if current[:until_end] > 365
+
+ long_output << current
+
# a contract is proposed to use after fday - 1, but before ldays.min (green)
# it is warned to user after fday - 1 but before lavg - 1 (red)
# it is warned red >= lavg - 1 and <= lavg + 1
color = if (ytoday >= lavg - 1) && (ytoday <= lavg + 1)
:light_red
@@ -394,57 +411,44 @@
elsif (ytoday >= (fday > lavg ? 0 : fday - 5)) && (ytoday <= ldays.min)
:light_green
else
:white
end
- # rubocop:disable Layout/ClosingParenthesisIndentation
- long_output << {
- month: month,
- first_ml: fday,
- last_min: ldays.min,
- last_avg: lavg,
- last_max: ldays.max }
+
output = "#{sym[:symbol]
- }#{month
- }\t#{format '%12s', sym[:type]
- }\ttoday is #{ytoday
- } -- median of first is #{fday
- }\tlast ranges from #{format '%5d', ldays.min
- }: #{dfm.call(ldays.min)
- }\t#{format '%5d', lavg
- }: #{dfm.call(lavg)
- }\tto #{format '%5d', ldays.max
- }: #{dfm.call(ldays.max)}".colorize(color)
- if debug || (color != :white)
- puts output unless silent
- end
- output_sent << "#{sym[:symbol]}#{month}" unless color == :white
- early_year ||= output
- next if silent or not (debug and debuglevel >= 2)
+ }#{month
+ }\t#{format '%12s', sym[:type]
+ }\ttoday is #{ytoday
+ } -- median of first is #{fday
+ }\tlast ranges from #{format '%5d', ldays.min
+ }: #{dfm.call(ldays.min)
+ }\t#{format '%5d', lavg
+ }: #{dfm.call(lavg)
+ }\tto #{format '%5d', ldays.max
+ }: #{dfm.call(ldays.max)}".colorize(color)
- v0.each do |contract, v1|
- puts "\t#{contract
- }\t#{v1.first[:date]
- } (#{format '%3d', Date.parse(v1.first[:date]).yday
- })\t#{Date.parse(v1.last[:date]).strftime('%a, %Y-%m-%d')
- } (#{Date.parse(v1.last[:date]).yday})" unless silent
- # rubocop:enable Layout/ClosingParenthesisIndentation
- end
+ if debug || (color != :white)
+ puts output unless silent
+ end
+ next if silent or not (debug and debuglevel >= 2)
+
+ v0.each do |contract, v1|
+ puts "\t#{contract
+ }\t#{v1.first[:date]
+ } (#{format '%3d', Date.parse(v1.first[:date]).yday
+ })\t#{Date.parse(v1.last[:date]).strftime('%a, %Y-%m-%d')
+ } (#{Date.parse(v1.last[:date]).yday})" unless silent
+ # rubocop:enable Layout/ClosingParenthesisIndentation
+ end
+
end
- case output_sent.size
- when 0
- unless silent
- puts "WARNING: No output was sent for symbol '#{sym[:symbol]}'.".colorize(:light_yellow)
- puts " Assuming late-year-processing.".light_yellow
- puts early_year.light_green
- end
- when 1
- # all ok
- true
- else
- puts "Continuous table show #{output_sent.size} active contracts ( #{output_sent} ) for #{sym[:symbol]} ---------------" unless silent
+ long_output.sort_by!{|z| z[:until_end] + (z[:until_end].negative? ? 365 : 0)}
+
+ if short
+ return ([long_output.first] + long_output.select{|z| z[:until_start].positive? and z[:until_start] < 10 }).map{|z| z[:contract] }.uniq
end
+
measuring.call("Finished processing")
- short ? output_sent : long_output
+ return long_output
end
end
end