lib/cotcube-bardata/eods.rb in cotcube-bardata-0.1.3 vs lib/cotcube-bardata/eods.rb in cotcube-bardata-0.1.4
- old
+ new
@@ -1,98 +1,121 @@
# frozen_string_literal: true
module Cotcube
+ # Missing top level documentation
module Bardata
-
- def most_liquid_for(symbol: nil, id: nil, date: last_trade_date, config: init, quiet: false)
- unless symbol.nil?
- symbol_id = symbols.select{|s| s[:symbol] == symbol.to_s.upcase}.first[:id]
- raise ArgumentError, "Could not find match in #{config[:symbols_file]} for given symbol #{symbol}" if symbol_id.nil?
- raise ArgumentError, "Mismatching symbol #{symbol} and given id #{id}" if not id.nil? and symbol_id != id
- id = symbol_id
- end
- raise ArgumentError, "Need :id or :symbol." if id.nil?
+ def most_liquid_for(symbol: nil, id: nil, date: last_trade_date, config: init)
+ id = get_id_set(symbol: symbol, id: id, config: config)[:id]
provide_eods(id: id, dates: date, contracts_only: true).first
end
- def provide_most_liquids_by_eod(config: init, date: last_trade_date, filter: :volume_part, age: 1.hour)
- eods = provide_eods(config: config, dates: date, filter: filter)
- result = []
+ # the following method seems to be garbage. It is not used anywhere. It seems it's purpose
+ # was to retrieve a list of quarters that have not been fetched recently (--> :age)
+ def provide_most_liquids_by_eod(symbol: nil, id: nil, # rubocop:disable Metrics/ParameterLists
+ config: init,
+ date: last_trade_date,
+ filter: :volume_part,
+ age: 1.hour)
+ sym = get_id_set(symbol: symbol, id: id) if symbol or id
+ eods = provide_eods(id: sym.nil? ? nil : sym[:id], config: config, dates: date, filter: filter)
+ result = []
eods.map do |eod|
symbol = eod[0..1]
- contract = eod[2..4]
- sym = symbols.select{|s| s[:symbol] == symbol.to_s.upcase}.first
+ contract = eod[2..4]
+ sym = symbols.select { |s| s[:symbol] == symbol.to_s.upcase }.first
quarter = "#{config[:data_path]}/quarters/#{sym[:id]}/#{contract}.csv"
if File.exist?(quarter)
- puts "#{quarter}: #{ Time.now } - #{File.mtime(quarter)} > #{age} : #{Time.now - File.mtime(quarter) > age}"
+ # puts "#{quarter}: #{ Time.now } - #{File.mtime(quarter)} > #{age} : #{Time.now - File.mtime(quarter) > age}"
result << eod if Time.now - File.mtime(quarter) > age
else
result << eod
end
end
result
end
- def provide_eods(symbol: nil,
- id: nil,
- contract: nil,
- config: init,
- dates: last_trade_date, # should accept either a date or datelike or date string OR a range of 2 datelike
+ # provide a list of all eods for id/symbol or all symbols (default) for an
+ # array of dates (default: [last_trade_date])
+ #
+ # filter by :threshold*100% share on entire volume(default) or oi
+ #
+ # return full data or just the contract name (default)
+ def provide_eods(symbol: nil, # rubocop:disable Metrics/ParameterLists
+ id: nil,
+ contract: nil,
+ config: init,
+ # should accept either a date or date_alike or date string OR a range of 2 dates alike
# if omitted returns the eods of last trading date
- threshold: 0.1, # set threshold to 0 to disable filtering at all. otherwise only contracts with partial of >= threshold are returned
- filter: :volume_part, # filter can be set to volume_part and oi_part. determines, which property is used for filtering.
- contracts_only: true # set to false to return the complete row instead of just the contracts matching filter and threshold
- )
- raise ArgumentError, "Contract '#{contract}' is bogus, should be like 'M21' or 'ESM21'" unless contract.nil? or (contract.is_a? String and [3,5].include? contract.size)
- if contract.to_s.size == 5
- symbol = contract[0..1]
- contract = contract[2..4]
+ dates: last_trade_date,
+ # set threshold to 0 to disable filtering at all.
+ # otherwise only contracts with partial of >= threshold are returned
+ threshold: 0.05,
+ # filter can be set to volume_part and oi_part.
+ # determines, which property is used for filtering.
+ filter: :volume_part,
+ # set to false to return the complete row instead
+ # of just the contracts matching filter and threshold
+ contracts_only: true,
+ quiet: false)
+ unless contract.nil? || (contract.is_a?(String) && [3, 5].include?(contract.size))
+ raise ArgumentError, "Contract '#{contract}' is bogus, should be like 'M21' or 'ESM21'"
end
- unless symbol.nil?
- symbol_id = symbols.select{|s| s[:symbol] == symbol.to_s.upcase}.first[:id]
- raise ArgumentError, "Could not find match in #{config[:symbols_file]} for given symbol #{symbol}" if symbol_id.nil?
- raise ArgumentError, "Mismatching symbol #{symbol} and given id #{id}" if not id.nil? and symbol_id != id
- id = symbol_id
- end
+
+ symbol = contract[0..1] if contract.to_s.size == 5
+ sym = get_id_set(symbol: symbol, id: id, config: config) if symbol || id
# if no id can be clarified from given arguments, return all matching contracts from all available symbols
# raise ArgumentError, "Could not guess :id or :symbol from 'contract: #{contract}', please clarify." if id.nil?
- raise ArgumentError, ":filter must be in [:volume_part, :oi_part]" unless [:volume_part, :oi_part].include? filter
+ raise ArgumentError, ':filter must be in [:volume_part, :oi_part]' unless %i[volume_part oi_part].include? filter
- ids = id.nil? ? symbols.map{|x| x[:id]} : [ id ]
- dates = [ dates ] unless dates.is_a? Array or dates.nil?
+ # noinspection RubyScope
+ ids = sym.nil? ? symbols.map { |x| x[:id] } : [sym[:id]]
+ dates = [dates] unless dates.is_a?(Array) || dates.nil?
- id_path_get = lambda {|_id| "#{config[:data_path]}/eods/#{_id}" }
+ id_path_get = ->(local_id) { "#{config[:data_path]}/eods/#{local_id}" }
- process_date_for_id = lambda do |d,i|
- sym = symbols.select{|s| s[:id] == i}.first
- symbol = sym[:symbol]
+ process_date_for_id = lambda do |d, i|
+ # l_sym = symbols.select { |s| s[:id] == i }.first
+ # l_symbol = l_sym[:symbol]
id_path = id_path_get.call(i)
data_file = "#{id_path}/#{d}.csv"
- raise RuntimeError, "No data found for requested :id (#{id_path} does not exist)" unless Dir.exist?(id_path)
+ raise "No data found for requested :id (#{id_path} does not exist)" unless Dir.exist?(id_path)
+
unless File.exist?(data_file)
- puts "WARNING: No data found for requested id/symbol #{id}/#{symbol} in #{id_path}.".light_yellow unless quiet
+ unless quiet
+ puts 'WARNING: No data found for requested id/symbol'\
+ " #{id}/#{symbol} in #{id_path} for #{d}.".colorize(:light_yellow)
+ end
return []
end
- data = CSV.read(data_file, headers: %i[contract date open high low close volume oi] ).map do |row|
+ data = CSV.read(data_file, headers: %i[contract date open high low close volume oi]).map do |row|
row = row.to_h
- row.each do |k, _|
- row[k] = row[k].to_f if [:open, :high, :low, :close].include? k
- row[k] = row[k].to_i if [:volume, :oi].include? k
+ row.each do |k, _|
+ row[k] = row[k].to_f if %i[open high low close].include? k
+ row[k] = row[k].to_i if %i[volume oi].include? k
end
row
end
- all_volume = data.map{|x| x[:volume] }.reduce(:+)
- all_oi = data.map{|x| x[:oi] }.reduce(:+)
- data.map{|x| x[:volume_part] = (x[:volume] / all_volume.to_f).round(4); x[:oi_part] = (x[:oi] / all_oi.to_f).round(4) }
- data.select{|x| x[filter] >= threshold}.sort_by{|x| -x[filter]}.tap{|x| x.map!{|y| y[:contract]} if contracts_only}
+ all_volume = data.map { |x| x[:volume] }.reduce(:+)
+ all_oi = data.map { |x| x[:oi] }.reduce(:+)
+ data.map do |x|
+ x[:volume_part] = (x[:volume] / all_volume.to_f).round(4)
+ x[:oi_part] = (x[:oi] / all_oi.to_f).round(4)
+ end
+ data.select { |x| x[filter] >= threshold }.sort_by { |x| -x[filter] }.tap do |x|
+ if contracts_only
+ x.map! do |y|
+ y[:contract]
+ end
+ end
+ end
end
if dates
- dates.map do |date|
- ids.map{|id| process_date_for_id.call(date, id) }
+ dates.map do |date|
+ ids.map { |local_id| process_date_for_id.call(date, local_id) }
end.flatten
else
- raise ArgumentError, "Sorry, support for unlimited dates is not implemented yet. Please send array of dates or single date"
+ raise ArgumentError,
+ 'Sorry, support for unlimited dates is not implemented yet. Please send array of dates or single date'
end
end
-
end
end