cotcube-bardata 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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