irix 2.4.2 → 2.4.5

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: c95445e49c906a31bbc9e16f2b4b78ca8d023fca73f5d29128d9531ab0112c18
4
- data.tar.gz: 79e6e7f4d815726d6624e4d79c0a0d8db2ebed9bda2534645c29b40bbffbf7d4
3
+ metadata.gz: f657a9eb4e3dfc49657b176fafc409ef49511836fffe48cfaa13d80b0d39368c
4
+ data.tar.gz: 00baaa01a84aafd3ff46ec00752fbd99705edf206a5e2c76483926555b1065e5
5
5
  SHA512:
6
- metadata.gz: '0509583f671a0de4396eaec6ae5cc524e0bf4924afb4186c7efa6487dfff53fcc657eccfdf53158a1e81deb3e24b7937a066a4c0e65669b209fda92c1c507133'
7
- data.tar.gz: d77b1f4410a5ff9d7ce1268aa30ea7e16556534f5684b3b14ddb241c6d9774e4c19518d92484d34cb8525818b53c3af72954f48eaf7782c1467bf6d3eef2b8d5
6
+ metadata.gz: d506765d1553093958e4597267bc0c3588648af480de6fb56ca9767c023ef17583a75da2c6806344e0732dd72a15fcd5ab650e0bb5a6d0bf6e469d699ef2709c
7
+ data.tar.gz: aafdb928c1c213c7685600a45812d0d1d630694c731b173ffdf2fe62155b4cf9de1fce67d039f5239590f670e004d3f86415375fbe786e3b7bcf0d206f1e81fa
data/.drone.yml CHANGED
@@ -9,6 +9,21 @@ steps:
9
9
  - gem install bundler:2.0.2
10
10
  - bundle install --jobs=$(nproc) --retry=3 --path vendor/bundle
11
11
  - bundle exec rspec
12
+
13
+ - name: Release gem
14
+ image: ruby:2.6
15
+ environment:
16
+ GEM_CREDENTIALS:
17
+ from_secret: gem_credentials
18
+ commands:
19
+ - mkdir -p ~/.gem
20
+ - echo $GEM_CREDENTIALS | base64 -d > ~/.gem/credentials
21
+ - chmod 0600 ~/.gem/credentials
22
+ - gem build irix.gemspec
23
+ - gem push irix-*.gem
24
+ when:
25
+ branch:
26
+ - master
12
27
 
13
28
  trigger:
14
29
  event:
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- irix (2.4.2)
4
+ irix (2.4.5)
5
5
  em-synchrony (~> 1.0)
6
6
  em-websocket
7
7
  eventmachine
@@ -22,13 +22,13 @@ GEM
22
22
  zeitwerk (~> 2.1, >= 2.1.8)
23
23
  addressable (2.7.0)
24
24
  public_suffix (>= 2.0.2, < 5.0)
25
- amq-protocol (2.3.0)
25
+ amq-protocol (2.3.1)
26
26
  amqp (1.8.0)
27
27
  amq-protocol (>= 2.2.0)
28
28
  eventmachine
29
29
  ast (2.4.0)
30
- bunny (2.14.4)
31
- amq-protocol (~> 2.3, >= 2.3.0)
30
+ bunny (2.15.0)
31
+ amq-protocol (~> 2.3, >= 2.3.1)
32
32
  byebug (11.1.1)
33
33
  clamp (1.3.1)
34
34
  coderay (1.1.2)
@@ -60,7 +60,7 @@ GEM
60
60
  multipart-post (>= 1.2, < 3)
61
61
  faraday_middleware (0.13.1)
62
62
  faraday (>= 0.7.4, < 1.0)
63
- faye (1.2.4)
63
+ faye (1.2.5)
64
64
  cookiejar (>= 0.3.0)
65
65
  em-http-request (>= 0.3.0)
66
66
  eventmachine (>= 0.12.0)
@@ -85,7 +85,7 @@ GEM
85
85
  parallel (1.19.0)
86
86
  parser (2.6.5.0)
87
87
  ast (~> 2.4.0)
88
- peatio (2.4.2)
88
+ peatio (2.4.4)
89
89
  activemodel (> 5.2, <= 6.0.0)
90
90
  amqp
91
91
  bunny
@@ -106,7 +106,7 @@ GEM
106
106
  pry-byebug (3.8.0)
107
107
  byebug (~> 11.0)
108
108
  pry (~> 0.10)
109
- public_suffix (4.0.3)
109
+ public_suffix (4.0.5)
110
110
  rack (2.2.2)
111
111
  rainbow (3.0.0)
112
112
  rake (13.0.1)
@@ -151,7 +151,7 @@ GEM
151
151
  eventmachine (~> 1.0, >= 1.0.4)
152
152
  rack (>= 1, < 3)
153
153
  thread_safe (0.3.6)
154
- tzinfo (1.2.6)
154
+ tzinfo (1.2.7)
155
155
  thread_safe (~> 0.1)
156
156
  unicode-display_width (1.6.0)
157
157
  websocket (1.2.8)
@@ -177,4 +177,4 @@ DEPENDENCIES
177
177
  simplecov-json
178
178
 
179
179
  BUNDLED WITH
180
- 2.0.2
180
+ 2.1.4
data/lib/irix/bitfinex.rb CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  module Irix
4
4
  class Bitfinex < Peatio::Upstream::Base
5
+ require 'time'
6
+
7
+ MIN_INCREMENT_COUNT_TO_SNAPSHOT = 100
8
+ MIN_PERIOD_TO_SNAPSHOT = 5
9
+ MAX_PERIOD_TO_SNAPSHOT = 60
10
+
11
+ attr_accessor :snap, :snapshot_time, :increment_count, :sequence_number,
12
+ :open_channels, :asks, :bids
13
+
5
14
  def initialize(config)
6
15
  super
7
16
  @connection = Faraday.new(url: (config['rest']).to_s) do |builder|
@@ -12,15 +21,22 @@ module Irix
12
21
  builder.ssl[:verify] = config['verify_ssl']
13
22
  end
14
23
  end
24
+ @open_channels = {}
15
25
  @ping_set = false
16
26
  @rest = (config['rest']).to_s
17
- @ws_url = "#{config['websocket']}"
27
+ @ws_url = (config['websocket']).to_s
18
28
  end
19
29
 
20
30
  def ws_connect
21
31
  super
22
32
  return if @ping_set
23
33
 
34
+ @ws.on(:open) do |_e|
35
+ subscribe_trades(@target, @ws)
36
+ subscribe_orderbook(@target, @ws)
37
+ logger.info { 'Websocket connected' }
38
+ end
39
+
24
40
  Fiber.new do
25
41
  EM::Synchrony.add_periodic_timer(80) do
26
42
  @ws.send('{"event":"ping"}')
@@ -30,6 +46,8 @@ module Irix
30
46
  end
31
47
 
32
48
  def subscribe_trades(market, ws)
49
+ return unless @config['trade_proxy']
50
+
33
51
  sub = {
34
52
  event: 'subscribe',
35
53
  channel: 'trades',
@@ -42,9 +60,40 @@ module Irix
42
60
  end
43
61
  end
44
62
 
63
+ def subscribe_orderbook(market, ws)
64
+ return unless @config['orderbook_proxy']
65
+
66
+ @sequence_number = 0
67
+ @increment_count = 0
68
+ @bids = []
69
+ @asks = []
70
+ @snap = { 'asks' => [], 'bids' => [] }
71
+ sub = {
72
+ event: 'subscribe',
73
+ channel: 'book',
74
+ symbol: market.upcase,
75
+ len: 25
76
+ }
77
+ Rails.logger.info 'Open event' + sub.to_s
78
+ EM.next_tick do
79
+ ws.send(JSON.generate(sub))
80
+ end
81
+ Fiber.new do
82
+ EM::Synchrony.add_periodic_timer(0.2) do
83
+ publish_increment
84
+ end
85
+ end.resume
86
+ end
87
+
45
88
  def ws_read_public_message(msg)
46
89
  if msg.is_a?(Array)
47
- detect_trade(msg)
90
+ if msg[1] == 'hb'
91
+ @ws.send('{"event":"ping"}')
92
+ elsif @open_channels[msg[0]] == 'trades'
93
+ detect_trade(msg)
94
+ elsif @open_channels[msg[0]] == 'book'
95
+ detect_order(msg)
96
+ end
48
97
  elsif msg.is_a?(Hash)
49
98
  message_event(msg)
50
99
  end
@@ -65,10 +114,85 @@ module Irix
65
114
  end
66
115
  end
67
116
 
117
+ # [
118
+ # CHANNEL_ID,
119
+ # [
120
+ # PRICE,
121
+ # COUNT,
122
+ # AMOUNT
123
+ # ]
124
+ # ]
125
+ def detect_order(msg)
126
+ if msg[1][0].is_a?(Array)
127
+ msg[1].each do |point|
128
+ if point[2] > 0
129
+ @snap['bids'] << [point[0].to_s, point[2].to_s]
130
+ else
131
+ @snap['asks'] << [point[0].to_s, point[2].abs.to_s]
132
+ end
133
+ end
134
+ publish_snapshot
135
+ else
136
+ if @increment_count < MIN_INCREMENT_COUNT_TO_SNAPSHOT && @snapshot_time <= Time.now - MAX_PERIOD_TO_SNAPSHOT
137
+ publish_snapshot
138
+ @increment_count = 0
139
+ elsif @increment_count >= MIN_INCREMENT_COUNT_TO_SNAPSHOT && @snapshot_time < Time.now - MIN_PERIOD_TO_SNAPSHOT
140
+ publish_snapshot
141
+ @increment_count = 0
142
+ end
143
+
144
+ fill_increment(msg[1])
145
+ end
146
+ end
147
+
148
+ def fill_increment(order)
149
+ side = order[2].positive? ? 'bid' : 'ask'
150
+ price = order[0].to_s
151
+ if order[1].zero?
152
+ amount = 0
153
+ @snap["#{side}s"].delete_if { |point| point[0] == price }
154
+ else
155
+ amount = order[2].abs.to_s
156
+ @snap["#{side}s"].delete_if { |point| point[0] == price }
157
+ @snap["#{side}s"] << [price.to_s, amount.to_s]
158
+ end
159
+ if side == 'bid'
160
+ @bids.delete_if { |point| point[0] == price }
161
+ @bids << [price.to_s, amount.to_s]
162
+ elsif side == 'ask'
163
+ @asks.delete_if { |point| point[0] == price }
164
+ @asks << [price.to_s, amount.to_s]
165
+ end
166
+ @increment_count += 1
167
+ end
168
+
169
+ def publish_increment
170
+ inc = {}
171
+ inc['bids'] = @bids.sort.reverse if @bids.present?
172
+ inc['asks'] = @asks.sort if @asks.present?
173
+ if inc.present?
174
+ @sequence_number += 1
175
+ @peatio_mq.enqueue_event('public', @market, 'ob-inc',
176
+ 'bids' => inc['bids'], 'asks' => inc['asks'],
177
+ 'sequence' => @sequence_number)
178
+ end
179
+ @bids = []
180
+ @asks = []
181
+ end
182
+
183
+ def publish_snapshot
184
+ @snapshot_time = Time.now
185
+ @peatio_mq.enqueue_event('public', @market, 'ob-snap',
186
+ 'bids' => @snap['bids'].sort.reverse,
187
+ 'asks' => @snap['asks'].sort,
188
+ 'sequence' => @sequence_number)
189
+ end
190
+
68
191
  def message_event(msg)
69
192
  case msg['event']
70
193
  when 'subscribed'
71
194
  Rails.logger.info "Event: #{msg}"
195
+ @open_channels[msg['chanId']] = msg['channel']
72
196
  when 'error'
73
197
  Rails.logger.info "Event: #{msg} ignored"
74
198
  end
data/lib/irix/huobi.rb CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  module Irix
4
4
  class Huobi < Peatio::Upstream::Base
5
+ require 'time'
6
+
7
+ MIN_INCREMENT_COUNT_TO_SNAPSHOT = 100
8
+ MIN_PERIOD_TO_SNAPSHOT = 5
9
+ MAX_PERIOD_TO_SNAPSHOT = 60
10
+
11
+ attr_accessor :snap, :snapshot_time, :increment_count, :sequence_number,
12
+ :asks, :bids
5
13
  # WS huobi global
6
14
  # websocket: "wss://api.huobi.pro/ws/"
7
15
  # WS for krw markets
@@ -37,11 +45,72 @@ module Irix
37
45
  end
38
46
 
39
47
  case msg['ch']
40
- when /market\.([^.]+)\.trade\.detail/
48
+ when /market\.#{@target}\.trade\.detail/
41
49
  detect_trade(msg.dig('tick', 'data'))
50
+ when /market\.#{@target}\.mbp\.150/
51
+ detect_order(msg.dig('tick'))
52
+ end
53
+ end
54
+
55
+ def detect_order(msg)
56
+ if @increment_count < MIN_INCREMENT_COUNT_TO_SNAPSHOT && @snapshot_time <= Time.now - MAX_PERIOD_TO_SNAPSHOT
57
+ publish_snapshot
58
+ @increment_count = 0
59
+ elsif @increment_count >= MIN_INCREMENT_COUNT_TO_SNAPSHOT && @snapshot_time < Time.now - MIN_PERIOD_TO_SNAPSHOT
60
+ publish_snapshot
61
+ @increment_count = 0
62
+ end
63
+ fill_increment(msg)
64
+ end
65
+
66
+ def fill_increment(inc)
67
+ fill_side(inc, "bids")
68
+ fill_side(inc, "asks")
69
+ @increment_count += 1
70
+ end
71
+
72
+ def fill_side(inc, side)
73
+ inc[side].each do |price_point|
74
+ price = price_point[0]
75
+ amount = price_point[1]
76
+ if amount.zero?
77
+ @snap[side].delete_if { |point| point[0] == price.to_s }
78
+ else
79
+ @snap[side].delete_if { |point| point[0] == price.to_s }
80
+ @snap[side] << [price.to_s, amount.to_s]
81
+ end
82
+ if side == "bids"
83
+ @bids.delete_if { |point| point[0] == price }
84
+ @bids << [price.to_s, amount.to_s]
85
+ elsif side == "asks"
86
+ @asks.delete_if { |point| point[0] == price }
87
+ @asks << [price.to_s, amount.to_s]
88
+ end
42
89
  end
43
90
  end
44
91
 
92
+ def publish_increment
93
+ inc = {}
94
+ inc['bids'] = @bids.sort.reverse if @bids.present?
95
+ inc['asks'] = @asks.sort if @asks.present?
96
+ if inc.present?
97
+ @sequence_number += 1
98
+ @peatio_mq.enqueue_event('public', @market, 'ob-inc',
99
+ 'bids' => inc['bids'], 'asks' => inc['asks'],
100
+ 'sequence' => @sequence_number)
101
+ end
102
+ @bids = []
103
+ @asks = []
104
+ end
105
+
106
+ def publish_snapshot
107
+ @snapshot_time = Time.now
108
+ @peatio_mq.enqueue_event('public', @market, 'ob-snap',
109
+ 'bids' => @snap['bids'].sort.reverse,
110
+ 'asks' => @snap['asks'].sort,
111
+ 'sequence' => @sequence_number)
112
+ end
113
+
45
114
  def detect_trade(msg)
46
115
  msg.map do |t|
47
116
  trade =
@@ -69,6 +138,8 @@ module Irix
69
138
  end
70
139
 
71
140
  def subscribe_trades(market, ws)
141
+ return unless @config['trade_proxy']
142
+
72
143
  sub = {
73
144
  'sub' => "market.#{market}.trade.detail"
74
145
  }
@@ -78,5 +149,29 @@ module Irix
78
149
  ws.send(JSON.generate(sub))
79
150
  end
80
151
  end
152
+
153
+ def subscribe_orderbook(market, ws)
154
+ return unless @config['orderbook_proxy']
155
+
156
+ @sequence_number = 0
157
+ @increment_count = 0
158
+ @snapshot_time = Time.now
159
+ @bids = []
160
+ @asks = []
161
+ @snap = { 'asks' => [], 'bids' => [] }
162
+ sub = {
163
+ 'sub' => "market.#{market}.mbp.150"
164
+ }
165
+
166
+ Rails.logger.info 'Open event' + sub.to_s
167
+ EM.next_tick do
168
+ ws.send(JSON.generate(sub))
169
+ end
170
+ Fiber.new do
171
+ EM::Synchrony.add_periodic_timer(0.2) do
172
+ publish_increment
173
+ end
174
+ end.resume
175
+ end
81
176
  end
82
177
  end
data/lib/irix/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Irix
2
- VERSION = "2.4.2"
2
+ VERSION = "2.4.5"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: irix
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.2
4
+ version: 2.4.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Naichuk M.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-24 00:00:00.000000000 Z
11
+ date: 2020-05-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: em-synchrony