cotcube-bardata 0.1.1 → 0.1.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: c4c50df76637c9cb761c86db2b64afe372f2dd6be052a11615b9b9e961c6c890
4
- data.tar.gz: 53eb198be134abc15d92e27eb34fa5b9482b964998e7016aedc9378a3199968c
3
+ metadata.gz: 7cc8f5a19330f55ec26073d90b2c7da30547b61903daa93f8b2977c05ad308f8
4
+ data.tar.gz: 3dac9e49fb0143d8dd91a86f5a7779dcb25a5c8fca719de5b23a46a5e742380f
5
5
  SHA512:
6
- metadata.gz: a15393072fd65a449cdeed625409bb175c3db7c10821d4727fa2aa62577897cf7350b97520f35c70e3485bcf74eab2b8f56ae814803ff77f0276de29957e1181
7
- data.tar.gz: 7c8b44f3a15abed527ff6be6c461fa786bfa2b73ca51b7aeeb718a28be38524a37788b5fab8e8513a4ede8318c134dafeda76a0171957244f75cd69668e20275
6
+ metadata.gz: aafb4160d474f4f4d0694faee22821f1e8a65a510dcc2c84999acce0e0f3b7511dc52cd2d28cb21856162fbed9c5fa2e9b8e65b8065b7c1603128f8ef1cdea75
7
+ data.tar.gz: 51ba4678419a6daf9f4d2a18810432f2f3c93c7a6417e8d0e7beae822e76ad9214450bfb1bf4479fc30c4032b51e4504c923e707f6ea8feff295f16071040df3
@@ -1,3 +1,12 @@
1
+ ## 0.1.2 (December 22, 2020)
2
+ - created and added .provide_quarters
3
+ - added cotcube-helpers as new dependency to gempsec
4
+ - added timezone to dailies and :datetime to each row
5
+ - updated master file with new methods and sub-file
6
+ - added eods with 2 simple mathods .most_liquid_for and .provide_eods
7
+ - added a simple getter to access CME tradedates (to fetch last_trade_date)
8
+ - moved daily stuff into new file, prepare .provide to become a major accessor method
9
+
1
10
  ## 0.1.1 (December 16, 2020)
2
11
 
3
12
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.1.2
@@ -27,6 +27,7 @@ Gem::Specification.new do |spec|
27
27
  spec.require_paths = ['lib']
28
28
 
29
29
  spec.add_dependency 'cotcube-indicators'
30
+ spec.add_dependency 'cotcube-helpers'
30
31
  spec.add_dependency 'yaml'
31
32
  spec.add_dependency 'activesupport'
32
33
  spec.add_dependency 'colorize'
@@ -1,34 +1,39 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'active_support'
4
+ require 'active_support/core_ext/time'
5
+ require 'active_support/core_ext/numeric'
4
6
  require 'colorize'
7
+ require 'httparty'
5
8
  require 'date' unless defined?(DateTime)
6
9
  require 'csv' unless defined?(CSV)
7
10
  require 'yaml' unless defined?(YAML)
8
- require 'httparty'
9
- require 'zip'
11
+ require 'cotcube-helpers'
12
+
10
13
 
11
14
 
12
15
  require_relative 'cotcube-bardata/constants'
13
16
  require_relative 'cotcube-bardata/init'
17
+ require_relative 'cotcube-bardata/trade_dates'
18
+ require_relative 'cotcube-bardata/daily'
19
+ require_relative 'cotcube-bardata/quarters'
20
+ require_relative 'cotcube-bardata/eods'
14
21
  require_relative 'cotcube-bardata/provide'
15
22
 
16
- private_files = Dir[__dir__ + '/cotcube-bardata/private/*.rb']
17
- private_files.each do |file|
18
- # puts 'Loading private module extension ' + file.chomp
19
- require file.chomp
20
- end
21
-
22
23
  module Cotcube
23
24
  module Bardata
24
25
 
25
26
  module_function :config_path, # provides the path of configuration directory
26
27
  :config_prefix, # provides the prefix of the configuration directory according to OS-specific FSH
27
28
  :init, # checks whether environment is prepared and returns the config hash
28
- :provide,
29
- :continuous,
30
- :continuous_overview,
31
-
29
+ :last_trade_date, # Provides the most recent trade date (today or maybe last friday before weekend)
30
+ :provide, #
31
+ :most_liquid_for, # the most_liquid contract for a given symbol or id, based on date or last_trade_date
32
+ :provide_eods, # provides the list of eods, either with data or just the contracts, filtered for liquidity threshold
33
+ :provide_daily, # provides the list of dailies for a given symbol, which include OI. Note that the close is settlement price.
34
+ :continuous, # for a given date or range, provide all contracts that exceed a given threshold of volume share
35
+ :continuous_overview, # based on continuous, create list of when which contract was most liquid
36
+ :provide_quarters, # provide the list of quarters, possibly as hours or days.
32
37
  :symbols # reads and provides the symbols file
33
38
 
34
39
  # please not that module_functions of source provided in private files must be published there
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cotcube
4
+ module Bardata
5
+
6
+ # just reads bardata/daily/<id>/<contract>.csv
7
+ def provide_daily(symbol: nil, id: nil, contract:, timezone: Time.find_zone('America/Chicago'), config: init)
8
+ contract = contract.to_s.upcase
9
+ raise ArgumentError, "Contract '#{contract}' is bogus, should be like 'M21' or 'ESM21'" unless contract.is_a? String and [3,5].include? contract.size
10
+ if contract.to_s.size == 5
11
+ symbol = contract[0..1]
12
+ contract = contract[2..4]
13
+ end
14
+ unless symbol.nil?
15
+ symbol_id = symbols.select{|s| s[:symbol] == symbol.to_s.upcase}.first[:id]
16
+ raise ArgumentError, "Could not find match in #{config[:symbols_file]} for given symbol #{symbol}" if symbol_id.nil?
17
+ raise ArgumentError, "Mismatching symbol #{symbol} and given id #{id}" if not id.nil? and symbol_id != id
18
+ id = symbol_id
19
+ end
20
+ raise ArgumentError, "Could not guess :id or :symbol from 'contract: #{contract}', please clarify." if id.nil?
21
+ id_path = "#{config[:data_path]}/daily/#{id}"
22
+ data_file = "#{id_path}/#{contract}.csv"
23
+ raise RuntimeError, "No data found for requested :id (#{id_path} does not exist)" unless Dir.exist?(id_path)
24
+ raise RuntimeError, "No data found for requested contract #{symbol}:#{contract} in #{id_path}." unless File.exist?(data_file)
25
+ data = CSV.read(data_file, headers: %i[contract date open high low close volume oi] ).map do |row|
26
+ row = row.to_h
27
+ row.each do |k, _|
28
+ row[k] = row[k].to_f if [:open, :high, :low, :close].include? k
29
+ row[k] = row[k].to_i if [:volume, :oi].include? k
30
+ end
31
+ row[:datetime] = timezone.parse(row[:date])
32
+ row
33
+ end
34
+ data
35
+ end
36
+
37
+ # reads all files in bardata/daily/<id> and aggregates by date (what is a pre-stage of a continuous based on daily bars)
38
+ def continuous(symbol: nil, id: nil, config: init, date: nil)
39
+ unless symbol.nil?
40
+ symbol_id = symbols.select{|s| s[:symbol] == symbol.to_s.upcase}.first[:id]
41
+ raise ArgumentError, "Could not find match in #{config[:symbols_file]} for given symbol #{symbol}" if symbol_id.nil?
42
+ raise ArgumentError, "Mismatching symbol #{symbol} and given id #{id}" if not id.nil? and symbol_id != id
43
+ id = symbol_id
44
+ end
45
+ raise ArgumentError, "Could not guess :id or :symbol, please clarify." if id.nil?
46
+ id_path = "#{config[:data_path]}/daily/#{id}"
47
+ available_contracts = Dir[id_path + '/*.csv'].map{|x| x.split('/').last.split('.').first}.sort_by{|x| x[-7]}.sort_by{|x| x[-6..-5]}
48
+ data = []
49
+ available_contracts.each do |c|
50
+ provide_daily(id: id, config: config, contract: c).each do |x|
51
+ data << x
52
+ end
53
+ end
54
+ result = []
55
+ data.sort_by{|x| x[:date]}.group_by{|x| x[:date]}.map{|k,v|
56
+ v.map{|x| x.delete(:date)}
57
+ result << {
58
+ date: k,
59
+ volume: v.map{|x| x[:volume]}.reduce(:+),
60
+ oi: v.map{|x| x[:oi ]}.reduce(:+)
61
+ }
62
+ result.last[:contracts] = v
63
+ }
64
+ date.nil? ? result : result.select{|x| x[:date] == date}.first
65
+ end
66
+
67
+ # based on .continuous, this methods sorts the prepared dailies continuous for each date on either :volume (default) or :oi
68
+ # with this job done, it can provide the period for which a past contract was the most liquid
69
+ #
70
+ def continuous_overview(symbol: nil, id: nil, config: init, selector: :volume, human: false, filter: nil)
71
+ raise ArgumentError, "Selector must be either :volume or :oi" unless selector.is_a? Symbol and [:volume, :oi].include? selector
72
+
73
+ unless symbol.nil?
74
+ symbol_id = symbols.select{|s| s[:symbol] == symbol.to_s.upcase}.first[:id]
75
+ raise ArgumentError, "Could not find match in #{config[:symbols_file]} for given symbol #{symbol}" if symbol_id.nil?
76
+ raise ArgumentError, "Mismatching symbol #{symbol} and given id #{id}" if not id.nil? and symbol_id != id
77
+ id = symbol_id
78
+ end
79
+ raise ArgumentError, "Could not guess :id or :symbol, please clarify." if id.nil?
80
+ data = continuous(id: id, config: config).map{|x|
81
+ {
82
+ date: x[:date],
83
+ volume: x[:contracts].sort_by{|x| - x[:volume]}[0..4].compact.select{|x| not x[:volume].zero?},
84
+ oi: x[:contracts].sort_by{|x| - x[:oi]}[0..4].compact.select{|x| not x[:oi].zero?}
85
+ }
86
+ }.select{|x| not x[selector].empty? }
87
+ result = data.group_by{|x| x[selector].first[:contract]}
88
+ if human
89
+ result.each {|k,v| puts "#{k}\t#{v.first[:date]}\t#{v.last[:date]}" if filter.nil? or v.first[selector].first[:contract][2..4]=~ /#{filter}/ }
90
+ end
91
+ result
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cotcube
4
+ module Bardata
5
+
6
+ def most_liquid_for(symbol: nil, id: nil, date: last_trade_date, config: init)
7
+ unless symbol.nil?
8
+ symbol_id = symbols.select{|s| s[:symbol] == symbol.to_s.upcase}.first[:id]
9
+ raise ArgumentError, "Could not find match in #{config[:symbols_file]} for given symbol #{symbol}" if symbol_id.nil?
10
+ raise ArgumentError, "Mismatching symbol #{symbol} and given id #{id}" if not id.nil? and symbol_id != id
11
+ id = symbol_id
12
+ end
13
+ raise ArgumentError, "Need :id or :symbol." if id.nil?
14
+ provide_eods(id: id, dates: date, contracts_only: true).first
15
+ end
16
+
17
+
18
+
19
+ def provide_eods(symbol: nil,
20
+ id: nil,
21
+ contract: nil,
22
+ config: init,
23
+ dates: last_trade_date, # should accept either a date or datelike or date string OR a range of 2 datelike
24
+ # if omitted returns the eods of last trading date
25
+ threshold: 0.1, # set threshold to 0 to disable filtering at all. otherwise only contracts with partial of >= threshold are returned
26
+ filter: :volume_part, # filter can be set to volume_part and oi_part. determines, which property is used for filtering.
27
+ contracts_only: true # set to false to return the complete row instead of just the contracts matching filter and threshold
28
+ )
29
+ 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)
30
+ if contract.to_s.size == 5
31
+ symbol = contract[0..1]
32
+ contract = contract[2..4]
33
+ end
34
+ unless symbol.nil?
35
+ symbol_id = symbols.select{|s| s[:symbol] == symbol.to_s.upcase}.first[:id]
36
+ raise ArgumentError, "Could not find match in #{config[:symbols_file]} for given symbol #{symbol}" if symbol_id.nil?
37
+ raise ArgumentError, "Mismatching symbol #{symbol} and given id #{id}" if not id.nil? and symbol_id != id
38
+ id = symbol_id
39
+ end
40
+ # if no id can be clarified from given arguments, return all matching contracts from all available symbols
41
+ # raise ArgumentError, "Could not guess :id or :symbol from 'contract: #{contract}', please clarify." if id.nil?
42
+ raise ArgumentError, ":filter must be in [:volume_part, :oi_part]" unless [:volume_part, :oi_part].include? filter
43
+
44
+ ids = id.nil? ? symbols.map{|x| x[:id]} : [ id ]
45
+ dates = [ dates ] unless dates.is_a? Array or dates.nil?
46
+
47
+ id_path_get = lambda {|_id| "#{config[:data_path]}/eods/#{_id}" }
48
+
49
+ process_date_for_id = lambda do |d,i|
50
+ sym = symbols.select{|s| s[:id] == i}.first
51
+ symbol = sym[:symbol]
52
+ id_path = id_path_get.call(i)
53
+ data_file = "#{id_path}/#{d}.csv"
54
+ raise RuntimeError, "No data found for requested :id (#{id_path} does not exist)" unless Dir.exist?(id_path)
55
+ raise RuntimeError, "No data found for requested contract #{symbol}:#{contract} in #{id_path}." unless File.exist?(data_file)
56
+ data = CSV.read(data_file, headers: %i[contract date open high low close volume oi] ).map do |row|
57
+ row = row.to_h
58
+ row.each do |k, _|
59
+ row[k] = row[k].to_f if [:open, :high, :low, :close].include? k
60
+ row[k] = row[k].to_i if [:volume, :oi].include? k
61
+ end
62
+ row
63
+ end
64
+ all_volume = data.map{|x| x[:volume] }.reduce(:+)
65
+ all_oi = data.map{|x| x[:oi] }.reduce(:+)
66
+ 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) }
67
+ data.select{|x| x[filter] >= threshold}.sort_by{|x| -x[filter]}.tap{|x| x.map!{|y| y[:contract]} if contracts_only}
68
+ end
69
+ if dates
70
+ dates.map do |date|
71
+ ids.map{|id| process_date_for_id.call(date, id) }
72
+ end.flatten
73
+ else
74
+ raise ArgumentError, "Sorry, support for unlimited dates is not implemented yet. Please send array of dates or single date"
75
+ end
76
+ end
77
+
78
+ end
79
+ end
@@ -3,85 +3,21 @@
3
3
  module Cotcube
4
4
  module Bardata
5
5
 
6
- def provide(symbol: nil, id: nil, contract:, config: init)
7
- raise ArgumentError, "Contract '#{contract}' is bogus, should be like 'M21' or 'ESM21'" unless contract.is_a? String and [3,5].include? contract.size
8
- if contract.to_s.size == 5
9
- symbol = contract[0..1]
10
- contract = contract[2..4]
6
+ def provide(symbol: nil, id: nil, contract:, config: init, date: Date.today - 1, type: nil, fill: :none)
7
+ case type
8
+ when :eod, :eods
9
+ provide_eods(symbol: symbol, id: id, contract: contract, date: date)
10
+ when :quarters
11
+ print :quarters
12
+ when :hours
13
+ print :hours
14
+ when :daily, :dailies
15
+ print :dailies
16
+ else
17
+ puts "WARNING: Using provide without :type is for legacy support pointing to .provide_daily".light_yellow
18
+ provide_daily(symbol: symbol, id: id, contract: contract, config: config)
11
19
  end
12
- unless symbol.nil?
13
- symbol_id = symbols.select{|s| s[:symbol] == symbol.to_s.upcase}.first[:id]
14
- raise ArgumentError, "Could not find match in #{config[:symbols_file]} for given symbol #{symbol}" if symbol_id.nil?
15
- raise ArgumentError, "Mismatching symbol #{symbol} and given id #{id}" if not id.nil? and symbol_id != id
16
- id = symbol_id
17
- end
18
- raise ArgumentError, "Could not guess :id or :symbol from 'contract: #{contract}', please clarify." if id.nil?
19
- id_path = "#{config[:data_path]}/daily/#{id}"
20
- data_file = "#{id_path}/#{contract}.csv"
21
- raise RuntimeError, "No data found for requested :id (#{id_path} does not exist)" unless Dir.exist?(id_path)
22
- raise RuntimeError, "No data found for requested contract #{symbol}:#{contract} in #{id_path}." unless File.exist?(data_file)
23
- data = CSV.read(data_file, headers: %i[contract date open high low close volume oi] ).map do |row|
24
- row = row.to_h
25
- row.each do |k, _|
26
- row[k] = row[k].to_f if [:open, :high, :low, :close].include? k
27
- row[k] = row[k].to_i if [:volume, :oi].include? k
28
- end
29
- row
30
- end
31
- data
32
- end
33
-
34
- def continuous(symbol: nil, id: nil, config: init)
35
- unless symbol.nil?
36
- symbol_id = symbols.select{|s| s[:symbol] == symbol.to_s.upcase}.first[:id]
37
- raise ArgumentError, "Could not find match in #{config[:symbols_file]} for given symbol #{symbol}" if symbol_id.nil?
38
- raise ArgumentError, "Mismatching symbol #{symbol} and given id #{id}" if not id.nil? and symbol_id != id
39
- id = symbol_id
40
- end
41
- raise ArgumentError, "Could not guess :id or :symbol, please clarify." if id.nil?
42
- id_path = "#{config[:data_path]}/daily/#{id}"
43
- available_contracts = Dir[id_path + '/*.csv'].map{|x| x.split('/').last.split('.').first}.sort_by{|x| x[-7]}.sort_by{|x| x[-6..-5]}
44
- data = []
45
- available_contracts.each do |c|
46
- provide(id: id, config: config, contract: c).each do |x|
47
- data << x
48
- end
49
- end
50
- result = []
51
- data.sort_by{|x| x[:date]}.group_by{|x| x[:date]}.map{|k,v|
52
- v.map{|x| x.delete(:date)}
53
- result << {
54
- date: k,
55
- volume: v.map{|x| x[:volume]}.reduce(:+),
56
- oi: v.map{|x| x[:oi ]}.reduce(:+)
57
- }
58
- result.last[:contracts] = v
59
- }
60
- result
61
- end
62
-
63
- def continuous_overview(symbol: nil, id: nil, config: init, selector: :volume, human: false, filter: nil)
64
- raise ArgumentError, "Selector must be either :volume or :oi" unless selector.is_a? Symbol and [:volume, :oi].include? selector
65
-
66
- unless symbol.nil?
67
- symbol_id = symbols.select{|s| s[:symbol] == symbol.to_s.upcase}.first[:id]
68
- raise ArgumentError, "Could not find match in #{config[:symbols_file]} for given symbol #{symbol}" if symbol_id.nil?
69
- raise ArgumentError, "Mismatching symbol #{symbol} and given id #{id}" if not id.nil? and symbol_id != id
70
- id = symbol_id
71
- end
72
- raise ArgumentError, "Could not guess :id or :symbol, please clarify." if id.nil?
73
- data = continuous(id: id, config: config).map{|x|
74
- {
75
- date: x[:date],
76
- volume: x[:contracts].sort_by{|x| - x[:volume]}[0..4].compact.select{|x| not x[:volume].zero?},
77
- oi: x[:contracts].sort_by{|x| - x[:oi]}[0..4].compact.select{|x| not x[:oi].zero?}
78
- }
79
- }.select{|x| not x[selector].empty? }
80
- result = data.group_by{|x| x[selector].first[:contract]}
81
- if human
82
- result.each {|k,v| puts "#{k}\t#{v.first[:date]}\t#{v.last[:date]}" if filter.nil? or v.first[selector].first[:contract][2..4]=~ /#{filter}/ }
83
- end
84
- result
85
20
  end
86
21
  end
22
+
87
23
  end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cotcube
4
+ module Bardata
5
+
6
+ def provide_quarters(
7
+ symbol: nil, id: nil,
8
+ contract:,
9
+ as: :quarters,
10
+ range: nil, date: nil,
11
+ timezone: Time.find_zone('America/Chicago'),
12
+ config: init,
13
+ quiet: false
14
+ )
15
+ date = timezone.parse(date) if date.is_a? String
16
+ raise ArgumentError, ":range and :date are mutually exclusive" if range and date
17
+ raise ArgumentError, "Contract '#{contract}' is bogus, should be like 'M21' or 'ESM21'" unless contract.is_a? String and [3,5].include? contract.size
18
+ if contract.to_s.size == 5
19
+ symbol = contract[0..1]
20
+ contract = contract[2..4]
21
+ end
22
+ unless symbol.nil?
23
+ symbol_id = symbols.select{|s| s[:symbol] == symbol.to_s.upcase}.first[:id]
24
+ raise ArgumentError, "Could not find match in #{config[:symbols_file]} for given symbol #{symbol}" if symbol_id.nil?
25
+ raise ArgumentError, "Mismatching symbol #{symbol} and given id #{id}" if not id.nil? and symbol_id != id
26
+ id = symbol_id
27
+ end
28
+ raise ArgumentError, ":as can only be in [:quarters, :hours, :days]" unless %i[quarters hours days].include?(as)
29
+ raise ArgumentError, "Could not guess :id or :symbol from 'contract: #{contract}', please clarify." if id.nil?
30
+ id_path = "#{config[:data_path]}/quarters/#{id}"
31
+ data_file = "#{id_path}/#{contract}.csv"
32
+ raise RuntimeError, "No data found for requested :id (#{id_path} does not exist)" unless Dir.exist?(id_path)
33
+ raise RuntimeError, "No data found for requested contract #{symbol}:#{contract} in #{id_path}." unless File.exist?(data_file)
34
+ data = CSV.read(data_file, headers: %i[contract datetime day open high low close volume]).map do |row|
35
+ row = row.to_h
36
+ %i[open high low close].map{|x| row[x] = row[x].to_f}
37
+ %i[volume day].map{|x| row[x] = row[x].to_i}
38
+ row[:datetime] = timezone.parse(row[:datetime])
39
+ row
40
+ end
41
+ select_specific_date = lambda do |specific_date|
42
+ data.select{|d| d[:day] == specific_date.day and specific_date.year == d[:datetime].year and (
43
+ if specific_date.day > 1
44
+ specific_date.month == d[:datetime].month
45
+ else
46
+ ((specific_date.month == d[:datetime].month and d[:datetime].day == 1) or
47
+ (specific_date.month == d[:datetime].month + 1 and d[:datetime].day > 25) )
48
+ end
49
+ )}
50
+ end
51
+ if range
52
+ starting = range.begin
53
+ starting = timezone.parse(starting) if starting.is_a? String
54
+ ending = range.end
55
+ ending = timezone.parse( ending) if ending.is_a? String
56
+ if starting.hour == 0 and starting.min == 0 and ending.hour == 0 and ending.min == 0
57
+ puts "WARNING: When sending midnight, full trading day is assumed (starting 5 pm yesterday, ending 4 pm today)".light_yellow unless quiet
58
+ result = select_specific_date.call(starting)
59
+ result += data.select{|d| d[:datetime] > starting and d[:datetime] < ending.to_date }
60
+ result += select_specific_date.call(ending)
61
+ result.uniq!
62
+ else
63
+ result = data.select{|x| x[:datetime] >= starting and x[:datetime] < ending }
64
+ end
65
+ elsif date
66
+ result = select_specific_date.call(date)
67
+ else
68
+ result = data
69
+ end
70
+ return case as
71
+ when :hours
72
+ Cotcube::Helpers.reduce(bars: result, to: 1.hour){|c,b| c[:day] == b[:day] and c[:datetime].hour == b[:datetime].hour }
73
+ when :days
74
+ Cotcube::Helpers.reduce(bars: result, to: 1.day ){|c,b| c[:day] == b[:day] }
75
+ else
76
+ result
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cotcube
4
+ module Bardata
5
+
6
+ # fetching official tradedates from CME
7
+ def last_trade_date
8
+ uri = "https://www.cmegroup.com/CmeWS/mvc/Volume/TradeDates?exchange=CME"
9
+ res = nil
10
+ res = HTTParty.get(uri).parsed_response
11
+ res.map{|x| a = x["tradeDate"].chars.each_slice(2).map(&:join); "#{a[0]}#{a[1]}-#{a[2]}-#{a[3]}"}.first
12
+ end
13
+
14
+ end
15
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cotcube-bardata
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.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: 2020-12-16 00:00:00.000000000 Z
11
+ date: 2020-12-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cotcube-indicators
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: cotcube-helpers
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: yaml
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -153,8 +167,12 @@ files:
153
167
  - cotcube-bardata.gemspec
154
168
  - lib/cotcube-bardata.rb
155
169
  - lib/cotcube-bardata/constants.rb
170
+ - lib/cotcube-bardata/daily.rb
171
+ - lib/cotcube-bardata/eods.rb
156
172
  - lib/cotcube-bardata/init.rb
157
173
  - lib/cotcube-bardata/provide.rb
174
+ - lib/cotcube-bardata/quarters.rb
175
+ - lib/cotcube-bardata/trade_dates.rb
158
176
  homepage: https://github.com/donkeybridge/cotcube-bardata
159
177
  licenses:
160
178
  - BSD-4-Clause