cotcube-bardata 0.1.2 → 0.1.7

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: 7cc8f5a19330f55ec26073d90b2c7da30547b61903daa93f8b2977c05ad308f8
4
- data.tar.gz: 3dac9e49fb0143d8dd91a86f5a7779dcb25a5c8fca719de5b23a46a5e742380f
3
+ metadata.gz: 7db21286fcb1a011326db3d27333b3417ec497db6c5b005250e0dcc11d355839
4
+ data.tar.gz: 1eca29b839ae84d43c601f793501237cabc5de25363ea1bd55f6c707393d98ba
5
5
  SHA512:
6
- metadata.gz: aafb4160d474f4f4d0694faee22821f1e8a65a510dcc2c84999acce0e0f3b7511dc52cd2d28cb21856162fbed9c5fa2e9b8e65b8065b7c1603128f8ef1cdea75
7
- data.tar.gz: 51ba4678419a6daf9f4d2a18810432f2f3c93c7a6417e8d0e7beae822e76ad9214450bfb1bf4479fc30c4032b51e4504c923e707f6ea8feff295f16071040df3
6
+ metadata.gz: 3b46cbfbd3bf8117a5076691d9eaa8985ea551d822838e69cf4336a97161e77d3c0ab5b9427f957a08a219a19290d76832527cadbf2956d16053762443e8f25b
7
+ data.tar.gz: b082544cd2ac1c4a36a5e23a7ce2da9764fd9ce4fa7f09a72b28a579301eb007fda3ea8c8856cb5f9a9fea6756d2c6ee2a4d84224195840793ff49d1c7985855
data/.irbrc.rb CHANGED
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  def verbose_toggle
2
- irb_context.echo ? irb_context.echo = false : irb_context.echo = true
4
+ irb_context.echo = (irb_context.echo ? false : true)
3
5
  end
4
6
 
5
7
  alias vt verbose_toggle
@@ -1,3 +1,41 @@
1
+ ## 0.1.7 (January 14, 2021)
2
+ - added :range parameter to :provide, hence to :provide_cached, :provide_daily
3
+ - added forgotten module_functions
4
+
5
+ ## 0.1.6 (January 07, 2021)
6
+ - prefering datetime instead date (in helpers and daily)
7
+ - changed keyword :set to :filter in cached, provide and trading_hours
8
+
9
+ ## 0.1.5 (January 02, 2021)
10
+ - applied some still missing cops
11
+
12
+ ## 0.1.4 (January 02, 2021)
13
+ - two minor fixes (cached.rb, daily.rb)
14
+ - adding first (shy) specs ... to be continued
15
+ - cotcube-bardata.rb: added dependency parallel, added new module files and functions
16
+ - provide.rb: writing provide, the central accessor to actual bardata
17
+ - cached.rb: implementing 'provide_cached', which manages reduced and dimished subsets of 'quarters'
18
+ - helpers.rb: added get_id_set
19
+ - daily.rb: applied cops
20
+ - quarters.rb: applied cops, used new get_id_set, slimmed down content in favor of 'provide'
21
+ - eods.rb: renamed get_id_from to get_id_set
22
+ - added explanation to range_matrix.rb
23
+ - added 'holidays' to trade_dates.csv, depending on according CSV
24
+ - applied cops to init.rb
25
+ - changed name from get_range to trading_hours
26
+ - minor change in gemspec
27
+ - fixed typos in README
28
+ - added bounded versions to gemspec
29
+ - applied cops
30
+ - new file trading_hours.rb providing get_range(). Based on CSV data it provides a list of ranges depicting seconds since Sunday 0:00am, which in turn can be used with the helper Array.new.to_time_interval.
31
+ - new file and method 'range_matrix', investigating high-low ranges of entire daily
32
+ - Too bad, found copied README...fixing something quite embarassing.
33
+
34
+ ## 0.1.3 (December 23, 2020)
35
+ - added .provide_most_liquids_by_eod which supports :age, filtering out files that have been updated more recently
36
+ - added 'type' to symbols to filter for e.g. currencies
37
+ - changed .provide_eods not to raise on missing eod-file but just to WARN
38
+
1
39
  ## 0.1.2 (December 22, 2020)
2
40
  - created and added .provide_quarters
3
41
  - added cotcube-helpers as new dependency to gempsec
data/Gemfile CHANGED
@@ -1,5 +1,6 @@
1
- source "https://rubygems.org"
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
2
4
 
3
5
  # Specify your gem's dependencies in bitangent.gemspec
4
6
  gemspec
5
-
data/README.md CHANGED
@@ -1,36 +1,19 @@
1
- # Bitangent
1
+ # cotcube-bardata
2
2
 
3
- This gem provides a class (and will maybe later provide a commandline tool) to process
4
- time series data into bitangents.
3
+ This gem is a versatile provider of bardata. It relies on a directory structure most probably saved to `/var/cotcube/bardata/`. The following directories and files contain data others might expect to be delivered by a database:
5
4
 
6
- The underlying algorithm starts with the entire range of data and shears it (starting at
7
- 90 or -90 degrees) along the x axis until a bitangent is found parallel to the x axis
8
- (i.e. __y == 0__ resp. __y == y.last__), resulting in an angle and a group of at least
9
- 2 measurements. Please note here:
10
- - Measurements can be clustered to 1 finding in case there is no significant distance to
11
- the bitangent in regard to the :fuzziness, which is at least 1 'tick'.
12
- - Ocassionally a bitangent becomes an N-tangent, when multiple findings or clusters are
13
- in one line resp. the fuzzied ranged on the sheared graph.
14
- - Shearing is limited by reaching 0 degrees, so everything below the horizont (or above resp.)
15
- is discarded.
16
-
17
- After identifiying the angle of Z degress delivering N findings( actually N - 1, as the
18
- last finding always is the last member of the series), the entire time series then is split
19
- into N subranges, where each subrange is processed again until it reaches minimum size
20
- (which defaults to 3 items).
21
-
22
- Except for the very first range the challenge is to trim away the beginning of each sub
23
- range.
24
-
25
- The result of such a search is a tree, where it might be considerable to walk and change
26
- this tree by adding elements to the time series instead of recalculating it completely.
5
+ 1. `eods`: within *eods/<id or symbol>/<date>.csv*, for each date a list of contracts is located, to be applied with the list of headers `%i[ contract date open high low close volume oi ]`.
6
+ 2. `daily`: within *daily/<id or symbol>/<contract>.csv*, for each contract all eods are provided. The list of headers is expected as `%i[ contract date open high low close volume oi ]`. Please note that it is not obvious whether `close` contains settlement or actual closing price, depending on the exchange and the broker providing the source data.
7
+ 3. `quarters`: within *quarters/<id or symbol>/<contract>.csv*, for each contract a list of quarters (15 minute intervals) is provided, depending on the first occurrence of the contract within the topN volume segment. Note the different headers here: `%i[ contract date_alike day open high low close volume ]`.
8
+ 4. `trading_hours`: within *trading_hours/<symbol or type>_<set>.csv* a list of intervals is provided, with the headers `%i[ interval_start interval_end ]` for each interval described by seconds since Sunday 0:00p.m. (as defaulted by Ruby's *DateTime.new.wday)*.
9
+ 5. `trade_dates.csv`: A growing list of trade\_dates as provided by the CME.
27
10
 
28
11
  ## Installation
29
12
 
30
13
  Add this line to your application's Gemfile:
31
14
 
32
15
  ```ruby
33
- gem 'bitangent'
16
+ gem 'cotcube-bardata'
34
17
  ```
35
18
 
36
19
  And then execute:
@@ -39,11 +22,60 @@ And then execute:
39
22
 
40
23
  Or install it yourself as:
41
24
 
42
- $ gem install bitangent
25
+ $ gem install cotcube-bardata
43
26
 
44
27
  ## Usage
45
28
 
46
- TODO: Write usage instructions here
29
+ ### Configuration
30
+
31
+ The gem expects a configfile 'bardata.yml', located in '/etc/cotcube/' on linux platform and '/usr/local/etc/cotcube/' on FreeBSD. The location of the configfile can be overwritten by passing the according parameter to `init`.
32
+
33
+ ### daily.rb
34
+
35
+ Provides
36
+
37
+ * `provide_daily(symbol: nil, id: nil, contract:, timezone: Time.find_zone('America/Chicago'), config: init)`
38
+ * `continuous(symbol: nil, id: nil, config: init, date: nil)`: Loads all dailies for given *id* and groups by date, hence providing a list of eods.
39
+ * `continuous_ml(symbol: nil, id: nil, base: nil)`: Provides a list of contracts, containing a list of most liquid by volume contracts as `{ date: , ml: }`
40
+ * `continuous_actual_ml(symbol: nil, id: nil)`: Same as above, but providing the succeeding trading day (as the signaled 'ML' is yet one day old before it can be used).
41
+ * `continuous_overview(symbol: nil, id: nil, config: init, selector: :volume, human: false, filter: nil)`: Several purposes, but most noticeable providing the range of first and last occurrence within the top N% by volume within eods.
42
+
43
+ ### eods.rb
44
+
45
+ Provides
46
+
47
+ * `most_liquid_for(symbol: nil, id: nil, date: last_trade_date, config: init, quiet: false)`
48
+ * `provide_most_liquids_by_eod(config: init, date: last_trade_date, filter: :volume_part, age: 1.hour)`
49
+ * `provide_eods(**args)`
50
+ * `provide_quarters(**args)`
51
+
52
+ ### quarters.rb
53
+
54
+ Provides `provide_quarters(**args)`.
55
+
56
+ ### provide.rb
57
+
58
+ Provides `provide(**args)`.
59
+
60
+ ### range\_matrix.rb
61
+
62
+ Provides `range_matrix`, a simple method processing data based on `Bardata.continuous_actual_ml` to return a statistical overview of daily high-low ranges (not True Ranges). It contains sets for
63
+
64
+ * all available data,
65
+ * a data subset containing the recent 12 months
66
+ * data diminished by `:dim` (top and bottom) based on all available data
67
+
68
+ and contains *max*, *avg*, *lower*, *median*, *upper* and *max* (where 'upper' and 'lower' are like the median but at the 25percentile and 75percentile resp.).
69
+
70
+ As a third dimension (sorry!) all of the above is applied to days, weeks as well as months.
71
+
72
+ ### trade\_dates.rb
73
+
74
+ Provides `last_trade_date`, simple fetches the current 5 trade dates from CME and returns the very last.
75
+
76
+ ### trading\_hours.rb
77
+
78
+ Provides `get_range(symbol: nil, set: :full, force_set: false, config: init, debug: false)`, loading a set of intervals. The sets are defaulting to :full when the requested set is not found--unless :force\_set is enabled. Furthermore, if symbol is not found, the type-based version is returned. Eventually, if neither could be returned, the 24x7 interval is returned.
47
79
 
48
80
  ## Development
49
81
 
@@ -53,9 +85,10 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
53
85
 
54
86
  ## Contributing
55
87
 
56
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/bitangent.
88
+ Bug reports and pull requests are welcome on GitHub at https://github.com/donkeybridge/bitangent.
57
89
 
58
90
 
59
91
  ## License
60
92
 
61
93
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
94
+
data/Rakefile CHANGED
@@ -1,6 +1,8 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
3
5
 
4
6
  RSpec::Core::RakeTask.new(:spec)
5
7
 
6
- task :default => :spec
8
+ task default: :spec
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.1.7
@@ -9,13 +9,13 @@ Gem::Specification.new do |spec|
9
9
  spec.summary = 'Functions to provide bardata; and some simple time series aggregations'
10
10
  spec.description = 'Functions to provide bardata; and some simple time series aggregations '
11
11
 
12
- spec.homepage = 'https://github.com/donkeybridge/'+ spec.name
12
+ spec.homepage = "https://github.com/donkeybridge/#{spec.name}"
13
13
  spec.license = 'BSD-4-Clause'
14
14
  spec.required_ruby_version = Gem::Requirement.new('~> 2.7')
15
15
 
16
16
  spec.metadata['homepage_uri'] = spec.homepage
17
17
  spec.metadata['source_code_uri'] = spec.homepage
18
- spec.metadata['changelog_uri'] = spec.homepage + '/CHANGELOG.md'
18
+ spec.metadata['changelog_uri'] = "#{spec.homepage}/CHANGELOG.md"
19
19
 
20
20
  # Specify which files should be added to the gem when it is released.
21
21
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -26,16 +26,15 @@ Gem::Specification.new do |spec|
26
26
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
27
  spec.require_paths = ['lib']
28
28
 
29
- spec.add_dependency 'cotcube-indicators'
30
- spec.add_dependency 'cotcube-helpers'
31
- spec.add_dependency 'yaml'
32
- spec.add_dependency 'activesupport'
33
- spec.add_dependency 'colorize'
34
- spec.add_dependency 'httparty'
35
- spec.add_dependency 'rubyzip'
29
+ spec.add_dependency 'activesupport', '~> 6'
30
+ spec.add_dependency 'colorize', '~> 0.8'
31
+ spec.add_dependency 'cotcube-helpers', '~> 0.1'
32
+ spec.add_dependency 'cotcube-indicators', '~> 0.1'
33
+ spec.add_dependency 'httparty', '~> 0.18'
34
+ spec.add_dependency 'parallel', '~> 1'
35
+ spec.add_dependency 'yaml', '~> 0.1'
36
36
 
37
-
38
- spec.add_development_dependency 'rake'
37
+ spec.add_development_dependency 'rake', '>= 12'
39
38
  spec.add_development_dependency 'rspec', '~>3.6'
40
39
  spec.add_development_dependency 'yard', '~>0.9'
41
40
  end
@@ -1,3 +1,5 @@
1
+ # rubocop:disable Naming/FileName
2
+ # rubocop:enable Naming/FileName
1
3
  # frozen_string_literal: true
2
4
 
3
5
  require 'active_support'
@@ -9,34 +11,62 @@ require 'date' unless defined?(DateTime)
9
11
  require 'csv' unless defined?(CSV)
10
12
  require 'yaml' unless defined?(YAML)
11
13
  require 'cotcube-helpers'
12
-
13
-
14
+ require 'parallel'
14
15
 
15
16
  require_relative 'cotcube-bardata/constants'
17
+ require_relative 'cotcube-bardata/helpers'
16
18
  require_relative 'cotcube-bardata/init'
17
19
  require_relative 'cotcube-bardata/trade_dates'
18
20
  require_relative 'cotcube-bardata/daily'
19
21
  require_relative 'cotcube-bardata/quarters'
20
22
  require_relative 'cotcube-bardata/eods'
23
+ require_relative 'cotcube-bardata/cached'
21
24
  require_relative 'cotcube-bardata/provide'
25
+ require_relative 'cotcube-bardata/range_matrix'
26
+ require_relative 'cotcube-bardata/trading_hours'
22
27
 
23
28
  module Cotcube
24
29
  module Bardata
25
-
26
30
  module_function :config_path, # provides the path of configuration directory
27
- :config_prefix, # provides the prefix of the configuration directory according to OS-specific FSH
28
- :init, # checks whether environment is prepared and returns the config hash
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.
37
- :symbols # reads and provides the symbols file
38
-
39
- # please not that module_functions of source provided in private files must be published there
31
+ # provides the prefix of the configuration directory according to OS-specific FSH
32
+ :config_prefix,
33
+ # checks whether environment is prepared and returns the config hash
34
+ :init,
35
+ # Provides the most recent trade date (today or maybe last friday before weekend)
36
+ :last_trade_date,
37
+ :provide,
38
+ # the most_liquid contract for a given symbol or id, based on date or last_trade_date
39
+ :most_liquid_for,
40
+ # provides the list of eods, either with data or just the contracts,
41
+ # filtered for liquidity threshold
42
+ :provide_eods,
43
+ :provide_most_liquids_by_eod,
44
+ # provides the list of dailies for a given symbol, which include OI.
45
+ # Note that the close is most probably settlement price.
46
+ :provide_daily,
47
+ # for a given date or range, provide all contracts that exceed a given threshold of volume share
48
+ :continuous,
49
+ # the list of most liquid contracts (by each days volume share)
50
+ :continuous_ml,
51
+ # same list but riped one day each
52
+ :continuous_actual_ml,
53
+ # based on continuous, create list of when which contract was most liquid
54
+ :continuous_overview,
55
+ # provide the list of quarters, possibly as hours or days.
56
+ :provide_quarters,
57
+ # some statistics to estimate daily volatility of specific contract
58
+ :range_matrix,
59
+ # create an array of ranges based on specified source data
60
+ :trading_hours,
61
+ # receive id / symbol information on an uncertain set of parameters
62
+ :get_id_set,
63
+ :select_specific_date,
64
+ :extended_select_for_range,
65
+ :provide_cached,
66
+ :compare,
67
+ :holidays,
68
+ :symbols # reads and provides the symbols file
69
+
70
+ # please note that module_functions of source provided in private files must be published there
40
71
  end
41
72
  end
42
-
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cotcube
4
+ # missing top level documentation
5
+ module Bardata
6
+ # send pre-created days based on quarters
7
+ def provide_cached(contract:, # rubocop:disable Metrics/ParameterLists
8
+ symbol: nil, id: nil,
9
+ range: nil,
10
+ config: init,
11
+ timezone: Time.find_zone('America/Chicago'),
12
+ filter: :full, # most probably either :full or :rth
13
+ force_update: false, # force reloading via provide_quarters
14
+ force_recent: false) #
15
+
16
+ unless range.nil? ||
17
+ range.is_a?(Range) &&
18
+ [Date, DateTime, ActiveSupport::TimeWithZone].map do |cl|
19
+ (range.begin.nil? || range.begin.is_a?(cl)) &&
20
+ (range.end.nil? || range.end.is_a?(cl))
21
+ end.reduce(:|)
22
+ raise ArgumentError, 'Range, if given, must be either (Integer..Integer) or (Timelike..Timelike)'
23
+ end
24
+
25
+ unless range.nil?
26
+ range_begin = range.begin.nil? ? nil : timezone.parse(range.begin.to_s)
27
+ range_end = range.end.nil? ? nil : timezone.parse(range.end.to_s)
28
+ range = (range_begin..range_end)
29
+ end
30
+
31
+ headers = %i[contract datetime open high low close volume]
32
+ sym = get_id_set(symbol: symbol, id: id, contract: contract)
33
+ contract = contract[-3..]
34
+ dir = "#{config[:data_path]}/cached/#{sym[:id]}_#{filter.to_s.downcase}"
35
+ symlink = "#{config[:data_path]}/cached/#{sym[:symbol]}_#{filter.to_s.downcase}"
36
+ `mkdir -p #{dir}` unless Dir.exist? dir
37
+ `ln -s #{dir} #{symlink}` unless File.exist? symlink
38
+ file = "#{dir}/#{contract}.csv"
39
+ quarters_file = "#{config[:data_path]}/quarters/#{sym[:id]}/#{contract[-3..]}.csv"
40
+ if File.exist?(file) && (not force_update)
41
+ base = CSV.read(file, headers: headers).map do |x|
42
+ x = x.to_h
43
+ x[:datetime] = timezone.parse(x[:datetime])
44
+ %i[open high low close].each { |z| x[z] = x[z].to_f.round(9) }
45
+ x[:volume] = x[:volume].to_i
46
+ x[:type] = "#{filter.to_s.downcase}_day".to_sym
47
+ x
48
+ end
49
+ if base.last[:high].zero?
50
+ # contract exists but is closed (has the CLOSED marker)
51
+ base.pop
52
+ # rubocop:disable Metrics/BlockNesting
53
+ result = if range.nil?
54
+ base
55
+ else
56
+ base.select do |x|
57
+ (range.begin.nil? ? true : x[:datetime] >= range.begin) and
58
+ (range.end.nil? ? true : x[:datetime] <= range.end)
59
+ end
60
+ end
61
+ return result
62
+ elsif File.mtime(file) < File.mtime(quarters_file)
63
+ result = if range.nil?
64
+ base
65
+ else
66
+ base.select do |x|
67
+ (range.begin.nil? ? true : x[:datetime] >= range.begin) and
68
+ (range.end.nil? ? true : x[:datetime] <= range.end)
69
+ end
70
+ end
71
+ # rubocop:enable Metrics/BlockNesting
72
+ return result
73
+ else
74
+ puts "File #{file} exists, but is neither closed nor current. Running update.".colorize(:light_green)
75
+ end
76
+ end
77
+ begin
78
+ data = provide_quarters(contract: contract, id: sym[:id], keep_marker: true)
79
+ rescue StandardError
80
+ puts "Cannot provide quarters for requested contract #{sym[:symbol]}:#{contract},"\
81
+ "returning '[ ]'".colorize(:light_red)
82
+ return []
83
+ end
84
+
85
+ # removing marker if existing
86
+ contract_is_marked = data.last[:high].zero?
87
+ data.pop if contract_is_marked
88
+ unless (filter == :full) || (data.size < 3)
89
+ requested_set = trading_hours(symbol: sym[:symbol], filter: filter)
90
+ data = data.select_within(ranges: requested_set, attr: :datetime) { |x| x.to_datetime.to_sssm }
91
+ end
92
+
93
+ base = Cotcube::Helpers.reduce(bars: data, to: :days)
94
+
95
+ # remove last day of result unless marked
96
+ base.pop unless contract_is_marked || force_recent
97
+
98
+ base.map do |x|
99
+ x[:datetime] = x[:datetime].to_date
100
+ x[:type] = "#{filter}_day".to_sym
101
+ x.delete(:day)
102
+ end
103
+ CSV.open(file, 'w') do |csv|
104
+ base.each { |b| csv << b.values_at(*headers) }
105
+ if contract_is_marked
106
+ marker = ["#{sym[:symbol]}#{contract}", base.last[:datetime] + 1.day, 0, 0, 0, 0, 0]
107
+ csv << marker
108
+ end
109
+ end
110
+ if range.nil?
111
+ base
112
+ else
113
+ base.select do |x|
114
+ (range.begin.nil? ? true : x[:date] >= range.begin) and
115
+ (range.end.nil? ? true : x[:date] <= range.end)
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end