tickseries 0.1.1alpha

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d71caec6e9a6de66e0d18b58a6dba5ef5d021d6ebf2c6b6b71fad151344676f3
4
+ data.tar.gz: ad25827c08d77046112df71758f920635d0ecb572ab8f8ca1e88eb3167257b14
5
+ SHA512:
6
+ metadata.gz: 175441d690488c3e66bf3682a03220bada56eed28fe3319450be662129aae245054fd85a6246a35ef871bd29de566de2c0d6a8b678c3cb4a9e10cb9386a5658d
7
+ data.tar.gz: bede548c0567dc07643538e3a905bd36e144854c82b3b3d56c99ff88d3123dc5a60e0bbe7c63db62c020acd74b9d6f9b94082f89f8fe29639167076006d839b8
data/.gitignore ADDED
@@ -0,0 +1,50 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+
13
+ # Used by dotenv library to load environment variables.
14
+ # .env
15
+
16
+ ## Specific to RubyMotion:
17
+ .dat*
18
+ .repl_history
19
+ build/
20
+ *.bridgesupport
21
+ build-iPhoneOS/
22
+ build-iPhoneSimulator/
23
+
24
+ ## Specific to RubyMotion (use of CocoaPods):
25
+ #
26
+ # We recommend against adding the Pods directory to your .gitignore. However
27
+ # you should judge for yourself, the pros and cons are mentioned at:
28
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
29
+ #
30
+ # vendor/Pods/
31
+
32
+ ## Documentation cache and generated files:
33
+ /.yardoc/
34
+ /_yardoc/
35
+ /doc/
36
+ /rdoc/
37
+
38
+ ## Environment normalization:
39
+ /.bundle/
40
+ /vendor/bundle
41
+ /lib/bundler/man/
42
+
43
+ # for a library or gem, you might want to ignore these files since the code is
44
+ # intended to run in multiple environments; otherwise, check them in:
45
+ # Gemfile.lock
46
+ # .ruby-version
47
+ # .ruby-gemset
48
+
49
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
50
+ .rvmrc
data/LICENSE ADDED
@@ -0,0 +1,29 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2019, Donkeybridge
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ 3. Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,19 @@
1
+ # TickSeries
2
+
3
+ TickSeries is a Ruby module including the classes
4
+ * Tick
5
+ * Series
6
+
7
+ It's purpose is to build a robust layer to working with single-valued timeseries.
8
+
9
+ ## Description
10
+
11
+ Description pending (as are tests).
12
+
13
+ ## Basic usage
14
+
15
+ > series = Series.load(file: "ticks-2019-04-01", symbol: "Voltage")
16
+ > series.select {|x| x.p > 5.1 }.each {|x| p x}
17
+
18
+
19
+
@@ -0,0 +1,13 @@
1
+ Feature: Initialization of Tick
2
+ Scenario: Initialization of Tick
3
+ When creating a tick without parameters it should raise ArgumentError
4
+
5
+ Scenario Outline: Initialization of Tick with different valid parameter types
6
+ When creating a tick with '<params>' it should result in <timestamp> and <price>
7
+ Examples:
8
+ | params | timestamp | price |
9
+ | {s: :foo, t: 1555767235, p: 123 } | 1555767235000 | 123.0 |
10
+ | {s: "foo", t: 1555767235123, p: 1.21 } | 1555767235123 | 1.21 |
11
+ | ["foo", "1555767235", "225" ] | 1555767235000 | 225.0 |
12
+ | :foo, 1555767235, 225 | 1555767235000 | 225.0 |
13
+ | 1555767235, 225 | 1555767235000 | 225.0 |
File without changes
@@ -0,0 +1,12 @@
1
+ require './lib/tickseries.rb'
2
+ include TickSeries
3
+
4
+ When "creating a tick without parameters it should raise ArgumentError" do
5
+ expect { Tick.new }.to raise_error(ArgumentError)
6
+ end
7
+
8
+ When /^creating a tick with '([^']*)' it should result in (\S*) and (\S*)$/ do |params, timestamp, price|
9
+ eval "@tick = Tick.new(#{params})"
10
+ expect(@tick.t).to eq(Integer(timestamp))
11
+ expect(@tick.p).to eq(BigDecimal(price,8))
12
+ end
@@ -0,0 +1,6 @@
1
+ require 'rspec'
2
+ RSpec.configure do |config|
3
+ config.expect_with :rspec do |c|
4
+ c.syntax = :expect
5
+ end
6
+ end
data/lib/tickseries.rb ADDED
@@ -0,0 +1,212 @@
1
+ require 'yaml'
2
+ require 'date'
3
+ require 'csv'
4
+ require 'bigdecimal'
5
+
6
+ # The module proveds TickSeries::Tick and TickSeries::Series
7
+ module TickSeries
8
+
9
+ # TickSeries::Series provides a TimeSeries (aka TickSeries) based on single Ticks (aka Measurements)
10
+ #
11
+ class Series
12
+
13
+ attr_reader :date, :ticks
14
+
15
+ # TickSeries::CONFIGFILEPATH
16
+ CONFIGFILEPATH = "~/.config/ez"
17
+ # TickSeries::CONFIGFILE basically contains the location of tickfiles as well as the location of symbol / contract information
18
+ #
19
+ CONFIGFILE = "#{CONFIGFILEPATH}/tickseries.conf"
20
+
21
+ # Helper method the read the config file
22
+ def self.get_config
23
+ begin
24
+ return YAML.load(File.read("#{`echo $HOME`.chomp}/.config/ez/tickseries.yml"))
25
+ rescue Errno::ENOENT
26
+ return {}
27
+ end
28
+ end
29
+
30
+ # Helper method the read the symbol config
31
+ def get_symbol_config
32
+ begin
33
+ return YAML.load(File.read("#{@symbolspath}/#{@symbol}.yml"))
34
+ #rescue Errno::ENOENT
35
+ # return {}
36
+ end
37
+ end
38
+
39
+ # Creates a new instance of TickSeries::Series. Accepts optionshash.
40
+ #
41
+ # @param opts [Hash]
42
+ def initialize(opts = {})
43
+
44
+ # Reading configfile and setting provided instance variables
45
+ `mkdir -p #{CONFIGFILEPATH} > /dev/null`
46
+ @config = Series.get_config
47
+ [:tickfilepath, :symbolspath].each do |param|
48
+ from_conf = @config[param.to_s] || @config[param]
49
+ from_opts = opts[param]
50
+ instance_variable_set("@#{param.to_s}", from_opts || from_conf)
51
+ end
52
+ p self.instance_variables
53
+
54
+ # Reading symbolconfig and providing instance variables
55
+ @symbol = opts[:symbol]
56
+ unless @symbol.nil?
57
+ @symbol = @symbol.upcase
58
+ @symbolconfig = self.get_symbol_config
59
+ p @symbolconfig
60
+ [:symbol, :ticksize].each do |param|
61
+ from_conf = @config[param.to_s] || @config[param]
62
+ from_opts = opts[param]
63
+ instance_variable_set("@#{param.to_s}", from_opts || from_conf)
64
+ end
65
+ end
66
+ @date ||= Date.today
67
+ @ticks = []
68
+ end
69
+
70
+ # Receptor from Enumerable#to_series
71
+ def self.from_enumerable(arr)
72
+ t = Series.new
73
+ arr.each{|x| t.add(x)}
74
+ t
75
+ end
76
+
77
+ # TickSeries::Series.load opens a 'tickfile' containing data saved as CSV.
78
+ def self.load(opts = {})
79
+ begin
80
+ config = Series.get_config
81
+ rescue Errno::ENOENT
82
+ config = {}
83
+ end
84
+ symbol = opts[:symbol]
85
+ file = opts[:file]
86
+ unless file.nil?
87
+ *path, filename = file.split('/')
88
+ if path.empty?
89
+ path = config[:tickfilepath] || config["tickfilepath"]
90
+ else
91
+ path = File.absolute_path(path.join('/'))
92
+ end
93
+ raise "Cannot guess tickfilepath from #{file}, please provide in #{CONFIGFILE}" if path.nil?
94
+
95
+ filetype = opts[:filetype] || filename.split('.').last
96
+ end
97
+ raise ArgumentError, "Cannot guess filetype for loading Timeseries from file #{path}/#{filename}" if filetype.nil?
98
+ raise ArgumentError, "Seems provided file for loading timeseries does not exist #{path}/#{filename}" unless File.file?("#{path}/#{filename}")
99
+
100
+ series = Series.new( symbol: opts[:symbol])
101
+
102
+ case filetype.downcase
103
+ when 'csv'
104
+ CSV.parse(`cat #{path}/#{filename} #{symbol.nil? ? "" : "| grep -i #{symbol}"}`).sort_by{|x| x[1] }.each{|x| series.add x}
105
+ else
106
+ raise(ArgumentError, "Unsupported filetype '.#{filetype}'")
107
+ end
108
+ series
109
+ end
110
+
111
+ # TickSeries::Series#add adds an element to series.
112
+ #
113
+ # element can be provided as TimeSeries::Tick, or as Hash or Array, that sufficises format requirements.
114
+ def add(element)
115
+ @ticks << ((element.is_a? Tick) ? element : Tick.new(element))
116
+ end
117
+
118
+ # @!visibility private
119
+ def map(&block); @ticks.map {|x| block.call(x)} ;end
120
+ # @!visibility private
121
+ def each(&block); @ticks.each {|x| block.call(x)} ;end
122
+ # @!visibility private
123
+ def each_with_index(&block); @ticks.each_with_index {|x,i| block.call(x,i)} ;end
124
+ # @!visibility private
125
+ def select(&block); @ticks.select {|x| block.call(x)} ;end
126
+ # @!visibility private
127
+ def reduce(c = 0, &block); @ticks.reduce(c) {|x,i| block.call(x,i)} ;end
128
+
129
+ # @!visibility private
130
+ def inspect
131
+ "<#TimeSeries::Series:0x#{self.object_id.to_s(16)} ticks: #{@ticks.size}, #{"symbol: #{@symbol}, " if @symbol}ticksize: #{@ticksize}, date: #{@date}>"
132
+ end
133
+ end
134
+
135
+ # TimeSeries::Series is the second part of the module. It contains a single measurement ("Messpunkt") of the series.
136
+ class Tick
137
+ attr_reader :t, :p, :v, :k
138
+
139
+ # The constructor is build as flexible as I was able to. It accepts
140
+ # * a Hash containing < :t | :time | :timestamp > with an integer or string value required in seconds or milliseconds
141
+ # containing < :m | :measurement | :price > with a Numeric value (can also be given as string)
142
+ # arbitrary information like or symbol, volume or peak information.
143
+ # * an Array that sufficises the expected order: < [ symbol,] timestamp, measure, frequency / volume, peak information >
144
+ def initialize(*args, &block)
145
+ raise ArgumentError, "Creating ticks without arguments is not supported" if args.empty?
146
+ opts = args[0] if args[0].is_a? Hash
147
+ args = args[0] if args[0].is_a? Array
148
+ if opts.nil?
149
+ prefix = 0
150
+ begin # if symbol is given on args[0], the Integer() will raise
151
+ timestamp = Integer(args[0])
152
+ rescue
153
+ prefix = 1
154
+ timestamp = Integer(args[1])
155
+ end
156
+ opts = {t: timestamp,
157
+ m: args[prefix + 1],
158
+ v: args[prefix + 2],
159
+ p: args[prefix + 3]}
160
+ end
161
+ @t = opts[:t] || opts[:time] || opts[:timestamp]
162
+ case @t
163
+ when *[Date, DateTime, Time]
164
+ @t = @t.to_time.to_i
165
+ when *[Integer, Float, BigDecimal]
166
+ @t = Integer(@t)
167
+ when String
168
+ failed = false
169
+ begin; @t = DateTime.parse(@t).to_time.to_i * 1000; rescue; failed = true; end
170
+ if failed; begin; @t = Integer(@t); failed = false; rescue; failed = true; end; end
171
+ raise ArgumentError, "Could not get Timestamp from given String #{@t}" if failed
172
+ else
173
+ raise ArgumentError, "Tick.new cannot continue without timestamp given as t:, time: timestamp: or within array."
174
+ end
175
+ if @t < 500000000000 # Tue, 05 Nov 1985 00:53:20 GMT in ms
176
+ # assume it was provided as second_based timestamp
177
+ @t *= 1000
178
+ end
179
+ raise ArgumentError, "Invalid timestamp, too small: #{@t} < 500000000000" if @t < 500000000000
180
+ @m = opts[:m] || opts[:measurement]
181
+ @m = BigDecimal(@m,8) unless @m.nil?
182
+ @v = opts[:v] || opts[:vol]
183
+ @v = @v.to_i unless @v.nil?
184
+ # :peak should only be set for peaks pointing out a deviation > 5 * @ticksize
185
+ @p = opts[:p] || opts[:peak]
186
+ @p = @p.to_i unless @p.nil?
187
+ end
188
+
189
+
190
+ # Convenient way to create a string representation of tick.
191
+ def to_s
192
+ "#{@t},#{@m.to_f},#{@v},#{@p}"
193
+ end
194
+
195
+ # TickSeries::Tick#human_time returns the time converted to a human readable format
196
+ #
197
+ # @param with_date [Boolean] whether or not to include Date information (default: false)
198
+ def human_time(with_date = false)
199
+ t = Time.at(@t / 1000)
200
+ t.strftime("#{ "%Y-%m-%d " if with_date }%H:%M:%S")
201
+ end
202
+ end
203
+ end
204
+
205
+ # Reopens enumerable to allow retransport into Series
206
+ # @!visibility private
207
+ module Enumerable
208
+ # @!visibility private
209
+ def to_series
210
+ TickSeries::Series.from_enumerable(self)
211
+ end
212
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tickseries
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1alpha
5
+ platform: ruby
6
+ authors:
7
+ - Benjamin L. Tischendorf
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-04-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: csv
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.6'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: cucumber
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.1'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: yard
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.9'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.9'
69
+ description: 'Ruby Module providing TickSeries::Tick and TickSeries::Series '
70
+ email: donkeybridge@jtown.eu
71
+ executables: []
72
+ extensions: []
73
+ extra_rdoc_files: []
74
+ files:
75
+ - ".gitignore"
76
+ - LICENSE
77
+ - README.md
78
+ - features/01-ticks-init.feature
79
+ - features/02-tickseries-init.feature
80
+ - features/step_definitions/01-ticks-init_steps.rb
81
+ - features/support/env.rb
82
+ - lib/tickseries.rb
83
+ homepage: https://github.com/donkeybridge/tickseries
84
+ licenses:
85
+ - BSD-4-Clause
86
+ metadata: {}
87
+ post_install_message:
88
+ rdoc_options: []
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '2.0'
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">"
99
+ - !ruby/object:Gem::Version
100
+ version: 1.3.1
101
+ requirements: []
102
+ rubyforge_project:
103
+ rubygems_version: 2.7.8
104
+ signing_key:
105
+ specification_version: 4
106
+ summary: Ruby Module providing TickSeries::Tick and TickSeries::Series
107
+ test_files:
108
+ - features/01-ticks-init.feature
109
+ - features/support/env.rb
110
+ - features/02-tickseries-init.feature
111
+ - features/step_definitions/01-ticks-init_steps.rb