timescaledb 0.2.6 → 0.2.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/timescaledb/acts_as_hypertable/core.rb +1 -1
- data/lib/timescaledb/database/quoting.rb +12 -0
- data/lib/timescaledb/database/schema_statements.rb +168 -0
- data/lib/timescaledb/database/types.rb +17 -0
- data/lib/timescaledb/database.rb +11 -0
- data/lib/timescaledb/toolkit/time_vector.rb +41 -4
- data/lib/timescaledb/version.rb +1 -1
- metadata +6 -95
- data/.github/workflows/ci.yml +0 -72
- data/.gitignore +0 -12
- data/.rspec +0 -3
- data/.ruby-version +0 -1
- data/.tool-versions +0 -1
- data/.travis.yml +0 -9
- data/CODE_OF_CONDUCT.md +0 -74
- data/Fastfile +0 -17
- data/Gemfile +0 -8
- data/Gemfile.lock +0 -75
- data/Gemfile.scenic +0 -7
- data/Gemfile.scenic.lock +0 -119
- data/README.md +0 -490
- data/Rakefile +0 -21
- data/bin/console +0 -28
- data/bin/setup +0 -13
- data/docs/command_line.md +0 -178
- data/docs/img/lttb_example.png +0 -0
- data/docs/img/lttb_sql_vs_ruby.gif +0 -0
- data/docs/img/lttb_zoom.gif +0 -0
- data/docs/index.md +0 -72
- data/docs/migrations.md +0 -76
- data/docs/models.md +0 -78
- data/docs/toolkit.md +0 -507
- data/docs/toolkit_lttb_tutorial.md +0 -557
- data/docs/toolkit_lttb_zoom.md +0 -357
- data/docs/toolkit_ohlc.md +0 -315
- data/docs/videos.md +0 -16
- data/examples/all_in_one/all_in_one.rb +0 -94
- data/examples/all_in_one/benchmark_comparison.rb +0 -108
- data/examples/all_in_one/caggs.rb +0 -93
- data/examples/all_in_one/query_data.rb +0 -78
- data/examples/ranking/.gitattributes +0 -7
- data/examples/ranking/.gitignore +0 -29
- data/examples/ranking/.ruby-version +0 -1
- data/examples/ranking/Gemfile +0 -33
- data/examples/ranking/Gemfile.lock +0 -189
- data/examples/ranking/README.md +0 -166
- data/examples/ranking/Rakefile +0 -6
- data/examples/ranking/app/controllers/application_controller.rb +0 -2
- data/examples/ranking/app/controllers/concerns/.keep +0 -0
- data/examples/ranking/app/jobs/application_job.rb +0 -7
- data/examples/ranking/app/models/application_record.rb +0 -3
- data/examples/ranking/app/models/concerns/.keep +0 -0
- data/examples/ranking/app/models/game.rb +0 -2
- data/examples/ranking/app/models/play.rb +0 -7
- data/examples/ranking/bin/bundle +0 -114
- data/examples/ranking/bin/rails +0 -4
- data/examples/ranking/bin/rake +0 -4
- data/examples/ranking/bin/setup +0 -33
- data/examples/ranking/config/application.rb +0 -39
- data/examples/ranking/config/boot.rb +0 -4
- data/examples/ranking/config/credentials.yml.enc +0 -1
- data/examples/ranking/config/database.yml +0 -86
- data/examples/ranking/config/environment.rb +0 -5
- data/examples/ranking/config/environments/development.rb +0 -60
- data/examples/ranking/config/environments/production.rb +0 -75
- data/examples/ranking/config/environments/test.rb +0 -53
- data/examples/ranking/config/initializers/cors.rb +0 -16
- data/examples/ranking/config/initializers/filter_parameter_logging.rb +0 -8
- data/examples/ranking/config/initializers/inflections.rb +0 -16
- data/examples/ranking/config/initializers/timescale.rb +0 -2
- data/examples/ranking/config/locales/en.yml +0 -33
- data/examples/ranking/config/puma.rb +0 -43
- data/examples/ranking/config/routes.rb +0 -6
- data/examples/ranking/config/storage.yml +0 -34
- data/examples/ranking/config.ru +0 -6
- data/examples/ranking/db/migrate/20220209120747_create_games.rb +0 -10
- data/examples/ranking/db/migrate/20220209120910_create_plays.rb +0 -19
- data/examples/ranking/db/migrate/20220209143347_create_score_per_hours.rb +0 -5
- data/examples/ranking/db/schema.rb +0 -47
- data/examples/ranking/db/seeds.rb +0 -7
- data/examples/ranking/db/views/score_per_hours_v01.sql +0 -7
- data/examples/ranking/lib/tasks/.keep +0 -0
- data/examples/ranking/log/.keep +0 -0
- data/examples/ranking/public/robots.txt +0 -1
- data/examples/ranking/storage/.keep +0 -0
- data/examples/ranking/tmp/.keep +0 -0
- data/examples/ranking/tmp/pids/.keep +0 -0
- data/examples/ranking/tmp/storage/.keep +0 -0
- data/examples/ranking/vendor/.keep +0 -0
- data/examples/toolkit-demo/compare_volatility.rb +0 -104
- data/examples/toolkit-demo/lttb/README.md +0 -15
- data/examples/toolkit-demo/lttb/lttb.rb +0 -92
- data/examples/toolkit-demo/lttb/lttb_sinatra.rb +0 -139
- data/examples/toolkit-demo/lttb/lttb_test.rb +0 -21
- data/examples/toolkit-demo/lttb/views/index.erb +0 -27
- data/examples/toolkit-demo/lttb-zoom/README.md +0 -13
- data/examples/toolkit-demo/lttb-zoom/lttb_zoomable.rb +0 -90
- data/examples/toolkit-demo/lttb-zoom/views/index.erb +0 -33
- data/examples/toolkit-demo/ohlc.rb +0 -175
- data/mkdocs.yml +0 -34
- data/timescaledb.gemspec +0 -40
@@ -1,139 +0,0 @@
|
|
1
|
-
# ruby lttb.rb postgres://user:pass@host:port/db_name
|
2
|
-
require 'bundler/inline' #require only what you need
|
3
|
-
|
4
|
-
gemfile(true) do
|
5
|
-
gem 'timescaledb', path: '../../..'
|
6
|
-
gem 'pry'
|
7
|
-
gem 'sinatra', require: false
|
8
|
-
gem 'sinatra-reloader', require: false
|
9
|
-
gem 'sinatra-cross_origin', require: false
|
10
|
-
gem 'chartkick'
|
11
|
-
end
|
12
|
-
|
13
|
-
require 'timescaledb/toolkit'
|
14
|
-
require 'sinatra'
|
15
|
-
require 'sinatra/json'
|
16
|
-
require 'sinatra/cross_origin'
|
17
|
-
require 'chartkick'
|
18
|
-
require_relative 'lttb'
|
19
|
-
|
20
|
-
PG_URI = ARGV.last
|
21
|
-
|
22
|
-
VALID_SIZES = %i[small med big]
|
23
|
-
def download_weather_dataset size: :small
|
24
|
-
unless VALID_SIZES.include?(size)
|
25
|
-
fail "Invalid size: #{size}. Valids are #{VALID_SIZES}"
|
26
|
-
end
|
27
|
-
url = "https://timescaledata.blob.core.windows.net/datasets/weather_#{size}.tar.gz"
|
28
|
-
puts "fetching #{size} weather dataset..."
|
29
|
-
system "wget \"#{url}\""
|
30
|
-
puts "done!"
|
31
|
-
end
|
32
|
-
|
33
|
-
def setup size: :small
|
34
|
-
file = "weather_#{size}.tar.gz"
|
35
|
-
download_weather_dataset(size: size) unless File.exists? file
|
36
|
-
puts "extracting #{file}"
|
37
|
-
system "tar -xvzf #{file} "
|
38
|
-
puts "creating data structures"
|
39
|
-
system "psql #{PG_URI} < weather.sql"
|
40
|
-
system %|psql #{PG_URI} -c "\\COPY locations FROM weather_#{size}_locations.csv CSV"|
|
41
|
-
system %|psql #{PG_URI} -c "\\COPY conditions FROM weather_#{size}_conditions.csv CSV"|
|
42
|
-
end
|
43
|
-
|
44
|
-
ActiveRecord::Base.establish_connection(PG_URI)
|
45
|
-
class Location < ActiveRecord::Base
|
46
|
-
self.primary_key = "device_id"
|
47
|
-
|
48
|
-
has_many :conditions, foreign_key: "device_id"
|
49
|
-
end
|
50
|
-
|
51
|
-
class Condition < ActiveRecord::Base
|
52
|
-
acts_as_hypertable time_column: "time"
|
53
|
-
acts_as_time_vector value_column: "temperature", segment_by: "device_id"
|
54
|
-
|
55
|
-
belongs_to :location, foreign_key: "device_id"
|
56
|
-
end
|
57
|
-
|
58
|
-
# Setup Hypertable as in a migration
|
59
|
-
ActiveRecord::Base.connection.instance_exec do
|
60
|
-
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
61
|
-
|
62
|
-
unless Condition.table_exists?
|
63
|
-
setup size: :big
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
require 'sinatra/reloader'
|
68
|
-
require 'sinatra/contrib'
|
69
|
-
register Sinatra::Reloader
|
70
|
-
register Sinatra::Contrib
|
71
|
-
include Chartkick::Helper
|
72
|
-
|
73
|
-
set :bind, '0.0.0.0'
|
74
|
-
set :port, 9999
|
75
|
-
|
76
|
-
def conditions
|
77
|
-
device_ids = (1..9).map{|i|"weather-pro-00000#{i}"}
|
78
|
-
Condition
|
79
|
-
.where(device_id: device_ids.first)
|
80
|
-
.order('time')
|
81
|
-
end
|
82
|
-
|
83
|
-
def threshold
|
84
|
-
params[:threshold]&.to_i || 50
|
85
|
-
end
|
86
|
-
|
87
|
-
configure do
|
88
|
-
enable :cross_origin
|
89
|
-
end
|
90
|
-
before do
|
91
|
-
response.headers['Access-Control-Allow-Origin'] = '*'
|
92
|
-
end
|
93
|
-
|
94
|
-
# routes...
|
95
|
-
options "*" do
|
96
|
-
response.headers["Allow"] = "GET, PUT, POST, DELETE, OPTIONS"
|
97
|
-
response.headers["Access-Control-Allow-Headers"] = "Authorization,
|
98
|
-
Content-Type, Accept, X-User-Email, X-Auth-Token"
|
99
|
-
response.headers["Access-Control-Allow-Origin"] = "*"
|
100
|
-
200
|
101
|
-
end
|
102
|
-
|
103
|
-
get '/' do
|
104
|
-
headers 'Access-Control-Allow-Origin' => 'https://cdn.jsdelivr.net/'
|
105
|
-
|
106
|
-
erb :index
|
107
|
-
end
|
108
|
-
|
109
|
-
get '/lttb_ruby' do
|
110
|
-
payload = conditions
|
111
|
-
.pluck(:device_id, :time, :temperature)
|
112
|
-
.group_by(&:first)
|
113
|
-
.map do |device_id, data|
|
114
|
-
data.each(&:shift)
|
115
|
-
{
|
116
|
-
name: device_id,
|
117
|
-
data: Lttb.downsample(data, threshold)
|
118
|
-
}
|
119
|
-
end
|
120
|
-
json payload
|
121
|
-
end
|
122
|
-
|
123
|
-
get "/lttb_sql" do
|
124
|
-
downsampled = conditions
|
125
|
-
.lttb(threshold: threshold)
|
126
|
-
.map do |device_id, data|
|
127
|
-
{
|
128
|
-
name: device_id,
|
129
|
-
data: data.sort_by(&:first)
|
130
|
-
}
|
131
|
-
end
|
132
|
-
json downsampled
|
133
|
-
end
|
134
|
-
|
135
|
-
|
136
|
-
get '/all_data' do
|
137
|
-
data = conditions.pluck(:time, :temperature)
|
138
|
-
json [ { name: "All data", data: data} ]
|
139
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
require_relative 'lttb'
|
2
|
-
require 'pp'
|
3
|
-
require 'date'
|
4
|
-
|
5
|
-
data = [
|
6
|
-
['2020-1-1', 10],
|
7
|
-
['2020-1-2', 21],
|
8
|
-
['2020-1-3', 19],
|
9
|
-
['2020-1-4', 32],
|
10
|
-
['2020-1-5', 12],
|
11
|
-
['2020-1-6', 14],
|
12
|
-
['2020-1-7', 18],
|
13
|
-
['2020-1-8', 29],
|
14
|
-
['2020-1-9', 23],
|
15
|
-
['2020-1-10', 27],
|
16
|
-
['2020-1-11', 14]]
|
17
|
-
data.each do |e|
|
18
|
-
e[0] = Time.mktime(*e[0].split('-'))
|
19
|
-
end
|
20
|
-
|
21
|
-
pp Lttb.downsample(data, 5)
|
@@ -1,27 +0,0 @@
|
|
1
|
-
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.1/dist/jquery.min.js"></script>
|
2
|
-
<script src="https://cdn.jsdelivr.net/npm/hammerjs@2.0.8hammerjs@2.0.8"></script>
|
3
|
-
<script src="https://cdn.jsdelivr.net/npm/moment@2.29.4/moment.min.js"></script>
|
4
|
-
<script src="https://cdn.jsdelivr.net/npm/highcharts@10.2.1/highcharts.min.js"></script>
|
5
|
-
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment@1.0.0/dist/chartjs-adapter-moment.min.js"></script>
|
6
|
-
<script src="https://cdn.jsdelivr.net/npm/chartkick@4.2.0/dist/chartkick.min.js"></script>
|
7
|
-
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-zoom@1.2.1/dist/chartjs-plugin-zoom.min.js"></script>
|
8
|
-
<h3>Downsampling <%= conditions.count %> records to
|
9
|
-
<select value="<%= threshold %>" onchange="location.href=`/?threshold=${this.value}`">
|
10
|
-
<option><%= threshold %></option>
|
11
|
-
<option value="50">50</option>
|
12
|
-
<option value="100">100</option>
|
13
|
-
<option value="500">500</option>
|
14
|
-
<option value="1000">1000</option>
|
15
|
-
<option value="5000">5000</option>
|
16
|
-
</select> points.
|
17
|
-
</h3>
|
18
|
-
|
19
|
-
<h3>SQL</h3>
|
20
|
-
<%= line_chart("/lttb_sql?threshold=#{threshold}",
|
21
|
-
loading: "dowsampled data from SQL") %>
|
22
|
-
<h3>Ruby</h3>
|
23
|
-
<%= line_chart("/lttb_ruby?threshold=#{threshold}",
|
24
|
-
library: {chart: {zoomType: 'x'}},
|
25
|
-
points: true, loading: "downsampled data from Ruby") %>
|
26
|
-
<!--%= line_chart("/all_data", loading: "Loading all data") %-->
|
27
|
-
|
@@ -1,13 +0,0 @@
|
|
1
|
-
# LTTB examples
|
2
|
-
|
3
|
-
This folder contains an example to explore the a dynamic reloading of downsampled data.
|
4
|
-
|
5
|
-
It keeps the same amount of data and refresh the data with a higher resolution
|
6
|
-
as you keep zooming in.
|
7
|
-
There is a [./lttb_zoomable.rb](./lttb_zoomable.rb) file is a small webserver that compares
|
8
|
-
the SQL vs Ruby implementation. It also uses the [./views](./views) folder which
|
9
|
-
contains the view with the rendering and javascript part.
|
10
|
-
|
11
|
-
You can learn more by reading the [LTTB Zoom tutorial](https://jonatas.github.io/timescaledb/toolkit_lttb_zoom/).
|
12
|
-
|
13
|
-
|
@@ -1,90 +0,0 @@
|
|
1
|
-
# ruby lttb_zoomable.rb postgres://user:pass@host:port/db_name
|
2
|
-
require 'bundler/inline' #require only what you need
|
3
|
-
|
4
|
-
gemfile(true) do
|
5
|
-
gem 'timescaledb', path: '../../..'
|
6
|
-
gem 'pry'
|
7
|
-
gem 'sinatra', require: false
|
8
|
-
gem 'sinatra-reloader'
|
9
|
-
gem 'sinatra-cross_origin'
|
10
|
-
end
|
11
|
-
|
12
|
-
require 'timescaledb/toolkit'
|
13
|
-
require 'sinatra'
|
14
|
-
require 'sinatra/json'
|
15
|
-
require 'sinatra/contrib'
|
16
|
-
|
17
|
-
register Sinatra::Reloader
|
18
|
-
register Sinatra::Contrib
|
19
|
-
|
20
|
-
PG_URI = ARGV.last
|
21
|
-
|
22
|
-
VALID_SIZES = %i[small med big]
|
23
|
-
def download_weather_dataset size: :small
|
24
|
-
unless VALID_SIZES.include?(size)
|
25
|
-
fail "Invalid size: #{size}. Valids are #{VALID_SIZES}"
|
26
|
-
end
|
27
|
-
url = "https://timescaledata.blob.core.windows.net/datasets/weather_#{size}.tar.gz"
|
28
|
-
puts "fetching #{size} weather dataset..."
|
29
|
-
system "wget \"#{url}\""
|
30
|
-
puts "done!"
|
31
|
-
end
|
32
|
-
|
33
|
-
def setup size: :small
|
34
|
-
file = "weather_#{size}.tar.gz"
|
35
|
-
download_weather_dataset(size: size) unless File.exists? file
|
36
|
-
puts "extracting #{file}"
|
37
|
-
system "tar -xvzf #{file} "
|
38
|
-
puts "creating data structures"
|
39
|
-
system "psql #{PG_URI} < weather.sql"
|
40
|
-
system %|psql #{PG_URI} -c "\\COPY locations FROM weather_#{size}_locations.csv CSV"|
|
41
|
-
system %|psql #{PG_URI} -c "\\COPY conditions FROM weather_#{size}_conditions.csv CSV"|
|
42
|
-
end
|
43
|
-
|
44
|
-
ActiveRecord::Base.establish_connection(PG_URI)
|
45
|
-
|
46
|
-
class Condition < ActiveRecord::Base
|
47
|
-
acts_as_hypertable time_column: "time"
|
48
|
-
acts_as_time_vector value_column: "temperature", segment_by: "device_id"
|
49
|
-
end
|
50
|
-
|
51
|
-
# Setup Hypertable as in a migration
|
52
|
-
ActiveRecord::Base.connection.instance_exec do
|
53
|
-
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
54
|
-
|
55
|
-
if !Condition.table_exists? || Condition.count.zero?
|
56
|
-
|
57
|
-
setup size: :big
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
|
62
|
-
def filter_by_request_params
|
63
|
-
filter= {device_id: "weather-pro-000001"}
|
64
|
-
if params[:filter] && params[:filter] != "null"
|
65
|
-
from, to = params[:filter].split(",").map(&Time.method(:parse))
|
66
|
-
filter[:time] = from..to
|
67
|
-
end
|
68
|
-
filter
|
69
|
-
end
|
70
|
-
|
71
|
-
def conditions
|
72
|
-
Condition.where(filter_by_request_params).order('time')
|
73
|
-
end
|
74
|
-
|
75
|
-
def threshold
|
76
|
-
params[:threshold]&.to_i || 50
|
77
|
-
end
|
78
|
-
|
79
|
-
configure do
|
80
|
-
enable :cross_origin
|
81
|
-
end
|
82
|
-
|
83
|
-
get '/' do
|
84
|
-
erb :index
|
85
|
-
end
|
86
|
-
|
87
|
-
get "/lttb_sql" do
|
88
|
-
downsampled = conditions.lttb(threshold: threshold, segment_by: nil)
|
89
|
-
json downsampled
|
90
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
<head>
|
2
|
-
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.1/dist/jquery.min.js"></script>
|
3
|
-
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
|
4
|
-
</head>
|
5
|
-
|
6
|
-
<h3>Downsampling <%= conditions.count %> records to
|
7
|
-
<select value="<%= threshold %>" onchange="location.href=`/?threshold=${this.value}`">
|
8
|
-
<option><%= threshold %></option>
|
9
|
-
<option value="50">50</option>
|
10
|
-
<option value="100">100</option>
|
11
|
-
<option value="500">500</option>
|
12
|
-
<option value="1000">1000</option>
|
13
|
-
<option value="5000">5000</option>
|
14
|
-
</select> points.
|
15
|
-
</h3>
|
16
|
-
<div id='container'></div>
|
17
|
-
<script>
|
18
|
-
let chart = document.getElementById('container');
|
19
|
-
function fetch(filter) {
|
20
|
-
$.ajax({
|
21
|
-
url: `/lttb_sql?threshold=<%= threshold %>&filter=${filter}`,
|
22
|
-
success: function(result) {
|
23
|
-
let x = result.map((e) => e[0]);
|
24
|
-
let y = result.map((e) => parseFloat(e[1]));
|
25
|
-
Plotly.newPlot(chart, [{x, y,"mode": "markers", "type": "scatter"}]);
|
26
|
-
chart.on('plotly_relayout',
|
27
|
-
function(eventdata){
|
28
|
-
fetch([eventdata['xaxis.range[0]'],eventdata['xaxis.range[1]']]);
|
29
|
-
});
|
30
|
-
}});
|
31
|
-
}
|
32
|
-
fetch(null);
|
33
|
-
</script>
|
@@ -1,175 +0,0 @@
|
|
1
|
-
# ruby ohlc.rb postgres://user:pass@host:port/db_name
|
2
|
-
# @see https://jonatas.github.io/timescaledb/ohlc_tutorial
|
3
|
-
|
4
|
-
require 'bundler/inline' #require only what you need
|
5
|
-
|
6
|
-
gemfile(true) do
|
7
|
-
gem 'timescaledb', path: '../..'
|
8
|
-
gem 'pry'
|
9
|
-
end
|
10
|
-
|
11
|
-
ActiveRecord::Base.establish_connection ARGV.last
|
12
|
-
|
13
|
-
# Compare ohlc processing in Ruby vs SQL.
|
14
|
-
class Tick < ActiveRecord::Base
|
15
|
-
acts_as_hypertable time_column: "time"
|
16
|
-
acts_as_time_vector segment_by: "symbol", value_column: "price"
|
17
|
-
end
|
18
|
-
require "active_support/concern"
|
19
|
-
|
20
|
-
module Ohlc
|
21
|
-
extend ActiveSupport::Concern
|
22
|
-
|
23
|
-
included do
|
24
|
-
%w[open high low close].each do |name|
|
25
|
-
attribute name, :decimal
|
26
|
-
attribute "#{name}_time", :time
|
27
|
-
end
|
28
|
-
|
29
|
-
|
30
|
-
scope :attributes, -> do
|
31
|
-
select("symbol, time,
|
32
|
-
toolkit_experimental.open(ohlc),
|
33
|
-
toolkit_experimental.high(ohlc),
|
34
|
-
toolkit_experimental.low(ohlc),
|
35
|
-
toolkit_experimental.close(ohlc),
|
36
|
-
toolkit_experimental.open_time(ohlc),
|
37
|
-
toolkit_experimental.high_time(ohlc),
|
38
|
-
toolkit_experimental.low_time(ohlc),
|
39
|
-
toolkit_experimental.close_time(ohlc)")
|
40
|
-
end
|
41
|
-
|
42
|
-
scope :rollup, -> (timeframe: '1h') do
|
43
|
-
select("symbol, time_bucket('#{timeframe}', time) as time,
|
44
|
-
toolkit_experimental.rollup(ohlc) as ohlc")
|
45
|
-
.group(1,2)
|
46
|
-
end
|
47
|
-
|
48
|
-
def readonly?
|
49
|
-
true
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
class_methods do
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
class Ohlc1m < ActiveRecord::Base
|
58
|
-
self.table_name = 'ohlc_1m'
|
59
|
-
include Ohlc
|
60
|
-
end
|
61
|
-
|
62
|
-
class Ohlc1h < ActiveRecord::Base
|
63
|
-
self.table_name = 'ohlc_1h'
|
64
|
-
include Ohlc
|
65
|
-
end
|
66
|
-
|
67
|
-
class Ohlc1d < ActiveRecord::Base
|
68
|
-
self.table_name = 'ohlc_1d'
|
69
|
-
include Ohlc
|
70
|
-
end
|
71
|
-
=begin
|
72
|
-
scope :ohlc_ruby, -> (
|
73
|
-
timeframe: 1.hour,
|
74
|
-
segment_by: segment_by_column,
|
75
|
-
time: time_column,
|
76
|
-
value: value_column) {
|
77
|
-
ohlcs = Hash.new() {|hash, key| hash[key] = [] }
|
78
|
-
|
79
|
-
key = tick.send(segment_by)
|
80
|
-
candlestick = ohlcs[key].last
|
81
|
-
if candlestick.nil? || candlestick.time + timeframe > tick.time
|
82
|
-
ohlcs[key] << Candlestick.new(time $, price)
|
83
|
-
end
|
84
|
-
find_all do |tick|
|
85
|
-
symbol = tick.symbol
|
86
|
-
|
87
|
-
if previous[symbol]
|
88
|
-
delta = (tick.price - previous[symbol]).abs
|
89
|
-
volatility[symbol] += delta
|
90
|
-
end
|
91
|
-
previous[symbol] = tick.price
|
92
|
-
end
|
93
|
-
volatility
|
94
|
-
}
|
95
|
-
=end
|
96
|
-
|
97
|
-
ActiveRecord::Base.connection.add_toolkit_to_search_path!
|
98
|
-
|
99
|
-
|
100
|
-
ActiveRecord::Base.connection.instance_exec do
|
101
|
-
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
102
|
-
|
103
|
-
unless Tick.table_exists?
|
104
|
-
hypertable_options = {
|
105
|
-
time_column: 'time',
|
106
|
-
chunk_time_interval: '1 week',
|
107
|
-
compress_segmentby: 'symbol',
|
108
|
-
compress_orderby: 'time',
|
109
|
-
compression_interval: '1 month'
|
110
|
-
}
|
111
|
-
create_table :ticks, hypertable: hypertable_options, id: false do |t|
|
112
|
-
t.column :time , 'timestamp with time zone'
|
113
|
-
t.string :symbol
|
114
|
-
t.decimal :price
|
115
|
-
t.integer :volume
|
116
|
-
end
|
117
|
-
|
118
|
-
options = {
|
119
|
-
with_data: false,
|
120
|
-
refresh_policies: {
|
121
|
-
start_offset: "INTERVAL '1 month'",
|
122
|
-
end_offset: "INTERVAL '1 minute'",
|
123
|
-
schedule_interval: "INTERVAL '1 minute'"
|
124
|
-
}
|
125
|
-
}
|
126
|
-
create_continuous_aggregate('ohlc_1m', Tick._ohlc(timeframe: '1m'), **options)
|
127
|
-
|
128
|
-
execute "CREATE VIEW ohlc_1h AS #{ Ohlc1m.rollup(timeframe: '1 hour').to_sql}"
|
129
|
-
execute "CREATE VIEW ohlc_1d AS #{ Ohlc1h.rollup(timeframe: '1 day').to_sql}"
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
if Tick.count.zero?
|
134
|
-
ActiveRecord::Base.connection.execute(<<~SQL)
|
135
|
-
INSERT INTO ticks
|
136
|
-
SELECT time, 'SYMBOL', 1 + (random()*30)::int, 100*(random()*10)::int
|
137
|
-
FROM generate_series(TIMESTAMP '2022-01-01 00:00:00',
|
138
|
-
TIMESTAMP '2022-02-01 00:01:00',
|
139
|
-
INTERVAL '1 second') AS time;
|
140
|
-
SQL
|
141
|
-
end
|
142
|
-
|
143
|
-
|
144
|
-
# Fetch attributes
|
145
|
-
Ohlc1m.attributes
|
146
|
-
|
147
|
-
# Rollup demo
|
148
|
-
|
149
|
-
# Attributes from rollup
|
150
|
-
Ohlc1m.attributes.from(Ohlc1m.rollup(timeframe: '1 day'))
|
151
|
-
|
152
|
-
|
153
|
-
# Nesting several levels
|
154
|
-
Ohlc1m.attributes.from(
|
155
|
-
Ohlc1m.rollup(timeframe: '1 week').from(
|
156
|
-
Ohlc1m.rollup(timeframe: '1 day')
|
157
|
-
)
|
158
|
-
)
|
159
|
-
Ohlc1m.attributes.from(
|
160
|
-
Ohlc1m.rollup(timeframe: '1 month').from(
|
161
|
-
Ohlc1m.rollup(timeframe: '1 week').from(
|
162
|
-
Ohlc1m.rollup(timeframe: '1 day')
|
163
|
-
)
|
164
|
-
)
|
165
|
-
)
|
166
|
-
|
167
|
-
Pry.start
|
168
|
-
|
169
|
-
=begin
|
170
|
-
TODO: implement the ohlc_ruby
|
171
|
-
Benchmark.bm do |x|
|
172
|
-
x.report("ruby") { Tick.ohlc_ruby }
|
173
|
-
x.report("sql") { Tick.ohlc.map(&:attributes) }
|
174
|
-
end
|
175
|
-
=end
|
data/mkdocs.yml
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
site_name: The Timescaledb gem
|
2
|
-
repo_url: https://github.com/jonatas/timescaledb
|
3
|
-
edit_uri: edit/master/docs/
|
4
|
-
extra:
|
5
|
-
analytics:
|
6
|
-
provider: google
|
7
|
-
property: G-9B2BMB0TNQ
|
8
|
-
theme:
|
9
|
-
name: material
|
10
|
-
palette:
|
11
|
-
primary: indigo
|
12
|
-
accent: pink
|
13
|
-
markdown_extensions:
|
14
|
-
- admonition
|
15
|
-
- codehilite:
|
16
|
-
guess_lang: false
|
17
|
-
- toc:
|
18
|
-
permalink: true
|
19
|
-
- pymdownx.highlight:
|
20
|
-
anchor_linenums: true
|
21
|
-
- pymdownx.inlinehilite
|
22
|
-
- pymdownx.snippets
|
23
|
-
- pymdownx.superfences
|
24
|
-
|
25
|
-
nav:
|
26
|
-
- Introduction: index.md
|
27
|
-
- Migrations: migrations.md
|
28
|
-
- Models: models.md
|
29
|
-
- Toolkit Integration: toolkit.md
|
30
|
-
- Toolkit LTTB Tutorial: toolkit_lttb_tutorial.md
|
31
|
-
- Zooming with High Resolution: toolkit_lttb_zoom.md
|
32
|
-
- Toolkit OHLC: toolkit_ohlc.md
|
33
|
-
- Command Line: command_line.md
|
34
|
-
- Videos: videos.md
|
data/timescaledb.gemspec
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
require_relative 'lib/timescaledb/version'
|
2
|
-
|
3
|
-
Gem::Specification.new do |spec|
|
4
|
-
spec.name = "timescaledb"
|
5
|
-
spec.version = Timescaledb::VERSION
|
6
|
-
spec.authors = ["Jônatas Davi Paganini"]
|
7
|
-
spec.email = ["jonatasdp@gmail.com"]
|
8
|
-
|
9
|
-
spec.summary = %q{TimescaleDB helpers for Ruby ecosystem.}
|
10
|
-
spec.description = %q{Functions from timescaledb available in the ActiveRecord models.}
|
11
|
-
spec.homepage = "https://github.com/jonatas/timescaledb"
|
12
|
-
spec.license = "MIT"
|
13
|
-
spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
|
14
|
-
|
15
|
-
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
16
|
-
|
17
|
-
spec.metadata["homepage_uri"] = spec.homepage
|
18
|
-
#spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
|
19
|
-
#spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
|
20
|
-
|
21
|
-
# Specify which files should be added to the gem when it is released.
|
22
|
-
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
23
|
-
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
24
|
-
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
25
|
-
end
|
26
|
-
spec.bindir = "bin"
|
27
|
-
spec.executables = spec.files.grep(%r{^bin/tsdb}) { |f| File.basename(f) }
|
28
|
-
spec.require_paths = ["lib"]
|
29
|
-
|
30
|
-
spec.add_dependency "pg", "~> 1.2"
|
31
|
-
spec.add_dependency "activerecord"
|
32
|
-
spec.add_dependency "activesupport"
|
33
|
-
|
34
|
-
spec.add_development_dependency "pry"
|
35
|
-
spec.add_development_dependency "rspec-its"
|
36
|
-
spec.add_development_dependency "rspec", "~> 3.0"
|
37
|
-
spec.add_development_dependency "dotenv"
|
38
|
-
spec.add_development_dependency "rake", "~> 12.0"
|
39
|
-
spec.add_development_dependency "database_cleaner-active_record"
|
40
|
-
end
|