cotcube-bardata 0.1.14 → 0.1.15.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: 6f517a7bf018413f424a2eba1e1c568c4db864240f88d23fe0c722526af858b4
4
- data.tar.gz: 7e303f08f4be6d64f1680f5107690e78525edcdf938245b22ab97a38af1523e7
3
+ metadata.gz: 46f85dd103fd911ba475b347f14002f1402eda630b79ded6a161969a1df487db
4
+ data.tar.gz: 72f66b63600041d28131df575036d0295f8ab206e132fcd69c2ea84109194505
5
5
  SHA512:
6
- metadata.gz: 5cbeae28346fca35de00cdc926724799f00c69ac8b023075c5dbd332327303ab457e1558eb289979ce95ef31b0cbc7e7cd1439ce550c4b2ddb415c79cffa21dd
7
- data.tar.gz: 9fcdc6b0b14212673d1c26e9c5b6b76264a2d8baa7270d609841377ad3fd753bb1011ddad499a27412e180dcbb8bc35a831e79e79c487866634f85533440b771
6
+ metadata.gz: 29271f6f4b5dba379bb19e81846d52f1d2995bd010f35b7e80bad3256ae415c841eeead6a84034ce72d29cd6b3746d4d62fb182347abca1fa6d78fd0c3bfb6a7
7
+ data.tar.gz: 5cb42e0fbd5ae2124edb7ede368047e72c8fe68b99ed928727d8e47859a5c94470bab989a032f0689e63058dd01b190936d02f22d8be7fca3cd61f3240a40a1c
data/CHANGELOG.md CHANGED
@@ -1,3 +1,20 @@
1
+ ## 0.1.15.2 (August 04, 2021)
2
+ - fixed leftover debug setting
3
+
4
+ ## 0.1.15.1 (August 04, 2021)
5
+ - fixed license mismatch
6
+
7
+ ## 0.1.15 (August 04, 2021)
8
+ - daily.rb: added support to add eod data on incomplete dailies
9
+ - adding dep: cotcube-indicators
10
+ - provide: new method :determine_significant_volume
11
+ - suggest: adding silence
12
+ - cached: Adding :dist
13
+ - daily: new method :determine_significant_volume
14
+ - added :dist generically to quarters
15
+ - trading_hours: added param to return headers only
16
+ - last_trade_date: Enabled caching instead of fetching each time
17
+
1
18
  ## 0.1.14 (May 07, 2021)
2
19
  - few changes in provide / cached / daily for a more straigtforward forcing of cache renewal
3
20
  - suggest: new method to suggest a contract for given symbol and date
data/README.md CHANGED
@@ -90,5 +90,5 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/donkey
90
90
 
91
91
  ## License
92
92
 
93
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
93
+ The gem is available as open source under the terms of the [BSD-3-Clause-License](https://opensource.org/licenses/BSD-3-Clause).
94
94
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.14
1
+ 0.1.15.2
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.description = 'Functions to provide bardata; and some simple time series aggregations '
11
11
 
12
12
  spec.homepage = "https://github.com/donkeybridge/#{spec.name}"
13
- spec.license = 'BSD-4-Clause'
13
+ spec.license = 'BSD-3-Clause'
14
14
  spec.required_ruby_version = Gem::Requirement.new('~> 2.7')
15
15
 
16
16
  spec.metadata['homepage_uri'] = spec.homepage
@@ -11,6 +11,7 @@ require 'date' unless defined?(DateTime)
11
11
  require 'csv' unless defined?(CSV)
12
12
  require 'yaml' unless defined?(YAML)
13
13
  require 'cotcube-helpers'
14
+ require 'cotcube-indicators'
14
15
  require 'parallel'
15
16
 
16
17
  require_relative 'cotcube-bardata/constants'
@@ -40,12 +40,13 @@ module Cotcube
40
40
  quarters_file = "#{config[:data_path]}/quarters/#{sym[:id]}/#{contract[-3..]}.csv"
41
41
  if File.exist?(file) && (not force_update)
42
42
  puts "Working with existing #{file}, no update was forced" if debug
43
- puts " Using quarters from #{quarters_file}"
43
+ puts " Using quarters from #{quarters_file}" if debug
44
44
  base = CSV.read(file, headers: headers).map do |x|
45
45
  x = x.to_h
46
46
  x[:datetime] = timezone.parse(x[:datetime])
47
47
  %i[open high low close].each { |z| x[z] = x[z].to_f.round(9) }
48
48
  x[:volume] = x[:volume].to_i
49
+ x[:dist] = ((x[:high] - x[:low]) / sym[:ticksize] ).to_i
49
50
  x[:type] = "#{filter.to_s.downcase}_day".to_sym
50
51
  x
51
52
  end
@@ -9,6 +9,7 @@ module Cotcube
9
9
  range: nil,
10
10
  timezone: Time.find_zone('America/Chicago'),
11
11
  keep_last: false,
12
+ add_eods: true,
12
13
  config: init)
13
14
  contract = contract.to_s.upcase
14
15
  unless contract.is_a?(String) && [3, 5].include?(contract.size)
@@ -46,10 +47,29 @@ module Cotcube
46
47
  row[k] = row[k].to_i if %i[volume oi].include? k
47
48
  end
48
49
  row[:datetime] = timezone.parse(row[:date])
50
+ row[:dist] = ((row[:high] - row[:low]) / sym[:ticksize] ).to_i
49
51
  row[:type] = :daily
50
52
  row
51
53
  end
52
- data.pop if data.last[:high].zero? and not keep_last
54
+ contract_expired = data.last[:high].zero?
55
+ data.pop if contract_expired and not keep_last
56
+ if not contract_expired and add_eods
57
+ today = Date.today
58
+ eods = [ ]
59
+ while today.strftime('%Y-%m-%d') > data.last[:date]
60
+ eods << provide_eods(symbol: sym[:symbol], dates: today, contracts_only: false)
61
+ today -= 1
62
+ end
63
+ eods.flatten!.map!{|x| x.tap {|y| %i[ volume_part oi_part ].map{|z| y.delete(z)} } }
64
+ eods.select{|x| x[:contract] == contract }
65
+ eods.map!{|x| x.tap{|y|
66
+ y[:datetime] = timezone.parse(y[:date])
67
+ y[:dist] = ((y[:high] - y[:low]) / sym[:ticksize] ).to_i
68
+ y[:type] = :eod
69
+ } }
70
+ data += eods.reverse
71
+
72
+ end
53
73
  if range.nil?
54
74
  data
55
75
  else
@@ -62,7 +82,7 @@ module Cotcube
62
82
 
63
83
  # reads all files in bardata/daily/<id> and aggregates by date
64
84
  # (what is a pre-stage of a continuous based on daily bars)
65
- def continuous(symbol: nil, id: nil, config: init, date: nil, measure: nil, force_rewrite: false)
85
+ def continuous(symbol: nil, id: nil, config: init, date: nil, measure: nil, force_rewrite: false, selector: nil, debug: false, add_eods: true)
66
86
  raise ArgumentError, ':measure, if given, must be a Time object (e.g. Time.now)' unless [NilClass, Time].include? measure.class
67
87
  measuring = lambda {|c| puts "[continuous] Time measured until '#{c}': #{(Time.now.to_f - measure.to_f).round(2)}sec" unless measure.nil? }
68
88
 
@@ -70,41 +90,117 @@ module Cotcube
70
90
  sym = get_id_set(symbol: symbol, id: id)
71
91
  id = sym[:id]
72
92
  symbol = sym[:symbol]
93
+ ticksize = sym[:ticksize]
94
+ effective_selector = selector || :volume
95
+ raise ArgumentError, 'selector must be in %i[ nil :volume ;oi].' unless [ nil, :volume, :oi ].include? selector
73
96
  id_path = "#{config[:data_path]}/daily/#{id}"
74
97
  c_file = "#{id_path}/continuous.csv"
98
+ puts "Using file #{c_file}" if debug
75
99
 
76
100
  # instead of using the provide_daily methods above, for this bulk operation a 'continuous.csv' is created
77
101
  # this boosts from 4.5sec to 0.3sec
78
102
  rewriting = force_rewrite or not(File.exist?(c_file)) or (Time.now - File.mtime(c_file) > 8.days)
79
103
  if rewriting
80
104
  puts "In daily+continuous: Rewriting #{c_file} #{force_rewrite ? "forcibly" : "due to fileage"}.".light_yellow
81
- `rm #{c_file}; find #{id_path} | xargs cat 2>/dev/null | grep -v '0,0,0,0' | sort -t, -k2 | cut -d, -f1,2,7,8 > #{c_file}`
105
+ `rm #{c_file}; find #{id_path} | xargs cat 2>/dev/null | grep -v ',0,' | grep -v ',0$'| sort -t, -k2 | cut -d, -f1-8 | grep ',.*,' | uniq > #{c_file}`
82
106
  end
83
107
  loading = lambda do
84
108
  data = CSV.read(c_file).map do |row|
85
109
  r = { contract: row[0],
86
110
  date: row[1],
87
- volume: row[2].to_i,
88
- oi: row[3].to_i
111
+ open: row[2],
112
+ high: row[3],
113
+ low: row[4],
114
+ close: row[5],
115
+ volume: row[6].to_i,
116
+ oi: row[7].to_i
89
117
  }
90
118
  end
119
+ if add_eods
120
+ today = Date.today
121
+ eods = [ ]
122
+ while today.strftime('%Y-%m-%d') > data.last[:date]
123
+ eods << provide_eods(symbol: symbol, dates: today, contracts_only: false)
124
+ today -= 1
125
+ end
126
+ eods.flatten!.map!{|x| x.tap {|y| %i[ volume_part oi_part ].map{|z| y.delete(z)} } }
127
+ eods.delete_if { |elem| elem.flatten.empty? }
128
+ data += eods.reverse
129
+
130
+ end
91
131
 
92
132
  measuring.call("Finished retrieving dailies.")
93
133
  result = []
134
+ rounding = 8 # sym[:format].split('.').last.to_i rescue 6
135
+ indicators ||= {
136
+ typical: Cotcube::Indicators.calc(a: :high, b: :low, c: :close) {|high, low, close| (high + low + close) / 3 },
137
+ sma250_high: Cotcube::Indicators.sma(key: :high, length: 250),
138
+ sma250_low: Cotcube::Indicators.sma(key: :low, length: 250),
139
+ sma250_typ: Cotcube::Indicators.sma(key: :typical, length: 250),
140
+ # sma60_typ: Cotcube::Indicators.sma(key: :typical, length: short),
141
+ # tr: Cotcube::Indicators.true_range,
142
+ # atr5: Cotcube::Indicators.sma(key: :tr, length: 5),
143
+ # dist_abs: Cotcube::Indicators.calc(a: :sma250_high, b: :sma250_low, c: :high, d: :low) do |sma_high, sma_low, high, low|
144
+ # if high > sma_high
145
+ # high - sma_high
146
+ # elsif sma_low > low
147
+ # low - sma_low
148
+ # else
149
+ # 0
150
+ # end
151
+ #end,
152
+ #dist_sma: Cotcube::Indicators.calc(a: :sma250_typ, b: :sma60_typ) do |sma250, sma60|
153
+ # sma60 - sma250
154
+ #end,
155
+ #dist_index: Cotcube::Indicators.index(key: :dist_abs, length: 60, abs: true),
156
+ #dev250_squared: Cotcube::Indicators.calc(a: :sma250_typ, b: :typical) {|sma, x| (sma - x) ** 2 },
157
+ #var250: Cotcube::Indicators.sma(key: :dev250_squared, length: long),
158
+ #sig250: Cotcube::Indicators.calc(a: :var250) {|var| Math.sqrt(var)},
159
+ #boll250_high: Cotcube::Indicators.calc(a: :sig250, b: :sma250_typ) {|sig, typ| (typ + sig * bollinger_factor) rescue nil},
160
+ #boll250_low: Cotcube::Indicators.calc(a: :sig250, b: :sma250_typ) {|sig, typ| (typ - sig * bollinger_factor) rescue nil},
161
+ #dev60_squared: Cotcube::Indicators.calc(a: :sma60_typ, b: :typical) {|sma, x| (sma - x) ** 2 },
162
+ #var60: Cotcube::Indicators.sma(key: :dev60_squared, length: short),
163
+ #sig60: Cotcube::Indicators.calc(a: :var60) {|var| Math.sqrt(var)},
164
+ #boll60_high: Cotcube::Indicators.calc(a: :sig60, b: :sma60_typ) {|sig, typ| (typ + sig * bollinger_factor) rescue nil},
165
+ #boll60_low: Cotcube::Indicators.calc(a: :sig60, b: :sma60_typ) {|sig, typ| (typ - sig * bollinger_factor) rescue nil}
166
+ dist: Cotcube::Indicators.calc(a: :high, b: :low, finalize: :to_i) {|high, low| ((high-low) / ticksize) }
167
+
168
+ }
169
+
170
+
171
+
94
172
  data.group_by { |x| x[:date] }.map do |k, v|
95
173
  v.map { |x| x.delete(:date) }
96
- result << {
174
+ avg_bar = {
97
175
  date: k,
98
- volume: v.map { |x| x[:volume] }.reduce(:+),
99
- oi: v.map { |x| x[:oi] }.reduce(:+)
176
+ contract: v.max_by{|x| x[:oi] }[:contract],
177
+ open: nil, high: nil, low: nil, close: nil,
178
+ volume: v.map { |x| x[:volume] }.reduce(:+),
179
+ oi: v.map { |x| x[:oi] }.reduce(:+),
180
+ }
181
+
182
+ %i[ open high low close ].each do |ohlc|
183
+ avg_bar[ohlc] = (v.map{|x| x[ohlc].to_f * x[effective_selector] }.reduce(:+) / avg_bar[effective_selector]).round(rounding)
184
+ end
185
+ p avg_bar if debug
186
+ indicators.each do |k,v|
187
+ print format('%12s: ', k.to_s) if debug
188
+ avg_bar[k] = v.call(avg_bar).round(rounding)
189
+ puts avg_bar[k] if debug
190
+ end
191
+ %i[tr atr5].each { |ind|
192
+ avg_bar[ind] = (avg_bar[ind] / sym[:ticksize]).round.to_i unless avg_bar[ind].nil?
100
193
  }
194
+ result << avg_bar
101
195
  result.last[:contracts] = v
102
196
  end
103
197
  result
104
198
  end
105
- constname = "CONTINUOUS_#{symbol}".to_sym
199
+ constname = "CONTINUOUS_#{symbol}#{selector.nil? ? '' : ('_' + selector.to_s)}".to_sym
106
200
  if rewriting or not Cotcube::Bardata.const_defined?( constname)
201
+ old = $VERBOSE; $VERBOSE = nil
107
202
  Cotcube::Bardata.const_set constname, loading.call
203
+ $VERBOSE = old
108
204
  end
109
205
  measuring.call("Finished processing")
110
206
  date.nil? ? Cotcube::Bardata.const_get(constname).map{|z| z.dup } : Cotcube::Bardata.const_get(constname).find { |x| x[:date] == date }
@@ -277,7 +373,7 @@ module Cotcube
277
373
  }\tto #{format '%5d', ldays.max
278
374
  }: #{dfm.call(ldays.max)}".colorize(color)
279
375
  if debug || (color != :white)
280
- puts output
376
+ puts output unless silent
281
377
  output_sent << "#{sym[:symbol]}#{month}" unless color == :white
282
378
  end
283
379
  early_year ||= output
@@ -288,20 +384,22 @@ module Cotcube
288
384
  }\t#{v1.first[:date]
289
385
  } (#{format '%3d', Date.parse(v1.first[:date]).yday
290
386
  })\t#{Date.parse(v1.last[:date]).strftime('%a, %Y-%m-%d')
291
- } (#{Date.parse(v1.last[:date]).yday})"
387
+ } (#{Date.parse(v1.last[:date]).yday})" unless silent
292
388
  # rubocop:enable Layout/ClosingParenthesisIndentation
293
389
  end
294
- end
390
+ end
295
391
  case output_sent.size
296
392
  when 0
297
- puts "WARNING: No output was sent for symbol '#{sym[:symbol]}'.".colorize(:light_yellow)
298
- puts " Assuming late-year-processing.".light_yellow
299
- puts early_year.light_green
393
+ unless silent
394
+ puts "WARNING: No output was sent for symbol '#{sym[:symbol]}'.".colorize(:light_yellow)
395
+ puts " Assuming late-year-processing.".light_yellow
396
+ puts early_year.light_green
397
+ end
300
398
  when 1
301
399
  # all ok
302
400
  true
303
401
  else
304
- puts "Continuous table show #{output_sent.size} active contracts ( #{output_sent} ) for #{sym[:symbol]} ---------------"
402
+ puts "Continuous table show #{output_sent.size} active contracts ( #{output_sent} ) for #{sym[:symbol]} ---------------" unless silent
305
403
  end
306
404
  measuring.call("Finished processing")
307
405
  short ? output_sent : long_output
@@ -54,5 +54,11 @@ module Cotcube
54
54
  raise ArgumentError, "Unsupported or unknown interval '#{interval}' in Bardata.provide"
55
55
  end
56
56
  end
57
+
58
+ def determine_significant_volume(base: , contract: )
59
+ set = Cotcube::Bardata.trading_hours(symbol: contract[0..1], filter: :rth)
60
+ prod = base - base.select_within(ranges: set ,attr: :datetime) {|x| x.to_datetime.to_sssm }
61
+ prod.group_by{|x| x[:volume] / 500 }
62
+ end
57
63
  end
58
64
  end
@@ -33,6 +33,7 @@ module Cotcube
33
33
  %i[open high low close].map { |x| row[x] = row[x].to_f }
34
34
  %i[volume day].map { |x| row[x] = row[x].to_i }
35
35
  row[:datetime] = timezone.parse(row[:datetime])
36
+ row[:dist] = ((row[:high] - row[:low]) / sym[:ticksize] ).to_i
36
37
  row[:type] = :quarter
37
38
  row
38
39
  end
@@ -5,7 +5,7 @@ module Cotcube
5
5
  module Bardata
6
6
  # based on day(of year) and symbol, suggest best fitting contract
7
7
  def suggest_contract_for symbol:, date: Date.today, warnings: true
8
- ml = Cotcube::Bardata.continuous_table symbol: symbol, date: date
8
+ ml = Cotcube::Bardata.continuous_table symbol: symbol, date: date, silent: true
9
9
  if ml.size != 1
10
10
  puts "WARNING: No or no unique most liquid found for #{date}. please give :contract parameter".light_yellow if warnings
11
11
  if ml.size > 1
@@ -5,19 +5,45 @@ module Cotcube
5
5
  module Bardata
6
6
  # fetching official trade dates from CME
7
7
  # it returns the current trade date or, if today isn't a trading day, the last trade date.
8
- def last_trade_date
9
- uri = 'https://www.cmegroup.com/CmeWS/mvc/Volume/TradeDates?exchange=CME'
10
- begin
11
- HTTParty.get(uri, headers: { "User-Agent" => "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/81.0"})
12
- .parsed_response
13
- .map do |x|
14
- a = x['tradeDate'].chars.each_slice(2).map(&:join)
15
- "#{a[0]}#{a[1]}-#{a[2]}-#{a[3]}"
16
- end
17
- .first
18
- rescue StandardError
19
- nil
8
+ def last_trade_date(force_update: false)
9
+ const_LTD = :LAST_TRADE_DATE
10
+ const_LTDU = :LAST_TRADE_DATE_UPDATE
11
+ if force_update or not Object.const_defined?(const_LTD) or Object.const_get(const_LTD).nil? or Time.now - Object.const_get(const_LTDU) > 2.hours
12
+ result = nil
13
+ uri = 'https://www.cmegroup.com/CmeWS/mvc/Volume/TradeDates?exchange=CME'
14
+ headers = { "Accept" => "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
15
+ "Accept-Encoding" => "gzip, deflate, br",
16
+ "Accept-Language" => "en-US,en;q=0.9",
17
+ "Cache-Control" => "max-age=0",
18
+ "Connection" => "keep-alive",
19
+ # Cookie: ak_bmsc=602078F6DE40954BAA8C7E7D3815102CACE82AAFD237000084B5A460F4FBCA68~pluz010T49Xag3sXquUZtVJmFX701dzEgt5v6Ht1EZSLKE4HL+bgg1L9ePnL5I0mm7QWXe1qaLhUbX1IPrL/f20trRMMRlkC3UWXk27DY/EBCP4mRno8QQygLCwgs2B2AQHJyb63WwRihCko8UYUiIhb89ArPZM5OPraoKy3JU9oE9e+iERdARNZHLHqRiB1GnmbKUvQqos3sXaEe3GpoiTszzk8sHZs4ZKuoO/rvFHko=",
20
+ "Host" => "www.cmegroup.com",
21
+ "sec-ch-ua" => %q[" Not A;Brand";v="99", "Chromium";v="90", "Google Chrome";v="90"],
22
+ "sec-ch-ua-mobile" => "?0",
23
+ "Sec-Fetch-Dest" => "document",
24
+ "Sec-Fetch-Mode" => "navigate",
25
+ "Sec-Fetch-Site" => "none",
26
+ "Sec-Fetch-User" => "?1",
27
+ "Upgrade-Insecure-Requests" => "1",
28
+ "User-Agent" => "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36" }
29
+ begin
30
+ # HTTParty.get(uri, headers: { "User-Agent" => "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/81.0"})
31
+ result = HTTParty.get(uri, headers: headers)
32
+ .parsed_response
33
+ .map do |x|
34
+ a = x['tradeDate'].chars.each_slice(2).map(&:join)
35
+ "#{a[0]}#{a[1]}-#{a[2]}-#{a[3]}"
36
+ end
37
+ .first
38
+ rescue StandardError
39
+ result = nil
40
+ end
41
+ oldverbose = $VERBOSE; $VERBOSE = nil
42
+ Object.const_set(const_LTD, result)
43
+ Object.const_set(const_LTDU, Time.now) unless result.nil?
44
+ $VERBOSE = oldverbose
20
45
  end
46
+ Object.const_get(const_LTD)
21
47
  end
22
48
 
23
49
  def holidays(config: init)
@@ -12,14 +12,20 @@ module Cotcube
12
12
  filter: ,
13
13
  force_filter: false, # with force_filter one would avoid falling back
14
14
  # to the contract_type based range set
15
+ headers_only: false, # return only headers instead of ranges
15
16
  config: init, debug: false)
16
17
  return (0...24 * 7 * 3600) if filter.to_s =~ /24x7/
17
18
 
18
19
  prepare = lambda do |f|
19
- CSV.read(f, converters: :numeric)
20
- .map(&:to_a)
21
- .tap { |x| x.shift unless x.first.first.is_a?(Numeric) }
22
- .map { |x| (x.first...x.last) }
20
+ if headers_only
21
+ CSV.read(f)
22
+ .first
23
+ else
24
+ CSV.read(f, converters: :numeric)
25
+ .map(&:to_a)
26
+ .tap { |x| x.shift unless x.first.first.is_a?(Numeric) }
27
+ .map { |x| (x.first...x.last) }
28
+ end
23
29
  end
24
30
 
25
31
  sym = get_id_set(symbol: symbol, id: id)
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.14
4
+ version: 0.1.15.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: 2021-05-07 00:00:00.000000000 Z
11
+ date: 2021-08-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -180,7 +180,7 @@ files:
180
180
  - lib/cotcube-bardata/trading_hours.rb
181
181
  homepage: https://github.com/donkeybridge/cotcube-bardata
182
182
  licenses:
183
- - BSD-4-Clause
183
+ - BSD-3-Clause
184
184
  metadata:
185
185
  homepage_uri: https://github.com/donkeybridge/cotcube-bardata
186
186
  source_code_uri: https://github.com/donkeybridge/cotcube-bardata