bitfinex-rb 0.1.0 → 1.0.0
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 +4 -4
- data/lib/bitfinex.rb +28 -30
- data/lib/{bitfinex/errors.rb → errors.rb} +2 -2
- data/lib/models/alert.rb +27 -0
- data/lib/models/balance_info.rb +25 -0
- data/lib/models/candle.rb +29 -0
- data/lib/models/currency.rb +27 -0
- data/lib/models/funding_credit.rb +41 -0
- data/lib/models/funding_info.rb +40 -0
- data/lib/models/funding_loan.rb +40 -0
- data/lib/models/funding_offer.rb +38 -0
- data/lib/models/funding_ticker.rb +50 -0
- data/lib/models/funding_trade.rb +31 -0
- data/lib/models/ledger_entry.rb +33 -0
- data/lib/models/margin_info.rb +67 -0
- data/lib/models/model.rb +56 -0
- data/lib/models/movement.rb +33 -0
- data/lib/models/notification.rb +30 -0
- data/lib/models/order.rb +197 -0
- data/lib/models/order_book.rb +265 -0
- data/lib/models/position.rb +33 -0
- data/lib/models/public_trade.rb +27 -0
- data/lib/models/trade.rb +34 -0
- data/lib/models/trading_ticker.rb +33 -0
- data/lib/models/user_info.rb +27 -0
- data/lib/models/wallet.rb +28 -0
- data/lib/rest/rest_client.rb +103 -0
- data/lib/rest/v1.rb +63 -0
- data/lib/rest/v1/account_info.rb +23 -0
- data/lib/{bitfinex → rest}/v1/deposit.rb +2 -3
- data/lib/{bitfinex → rest}/v1/funding_book.rb +2 -4
- data/lib/{bitfinex → rest}/v1/historical_data.rb +2 -2
- data/lib/{bitfinex → rest}/v1/lends.rb +1 -2
- data/lib/{bitfinex → rest}/v1/margin_funding.rb +1 -2
- data/lib/rest/v1/order_book.rb +17 -0
- data/lib/{bitfinex → rest}/v1/orders.rb +6 -8
- data/lib/{bitfinex → rest}/v1/positions.rb +6 -2
- data/lib/{bitfinex → rest}/v1/stats.rb +1 -3
- data/lib/{bitfinex → rest}/v1/symbols.rb +1 -2
- data/lib/rest/v1/ticker.rb +13 -0
- data/lib/{bitfinex → rest}/v1/trades.rb +1 -16
- data/lib/{bitfinex → rest}/v1/wallet.rb +1 -2
- data/lib/rest/v2.rb +47 -0
- data/lib/{bitfinex → rest}/v2/margin.rb +1 -2
- data/lib/{bitfinex → rest}/v2/personal.rb +2 -18
- data/lib/{bitfinex → rest}/v2/stats.rb +1 -4
- data/lib/rest/v2/ticker.rb +20 -0
- data/lib/{bitfinex → rest}/v2/trading.rb +3 -49
- data/lib/{bitfinex → rest}/v2/utils.rb +1 -3
- data/lib/ws/ws2.rb +529 -0
- metadata +74 -56
- data/lib/bitfinex-api-rb.rb +0 -1
- data/lib/bitfinex-rb.rb +0 -1
- data/lib/bitfinex/api_versions.rb +0 -7
- data/lib/bitfinex/authenticated_rest.rb +0 -57
- data/lib/bitfinex/client.rb +0 -38
- data/lib/bitfinex/configurable.rb +0 -48
- data/lib/bitfinex/connection.rb +0 -52
- data/lib/bitfinex/v1/account_info.rb +0 -38
- data/lib/bitfinex/v1/orderbook.rb +0 -36
- data/lib/bitfinex/v1/ticker.rb +0 -27
- data/lib/bitfinex/v2/ticker.rb +0 -58
- data/lib/bitfinex/version.rb +0 -3
- data/lib/bitfinex/websocket_connection.rb +0 -231
@@ -0,0 +1,33 @@
|
|
1
|
+
require_relative './model'
|
2
|
+
|
3
|
+
module Bitfinex
|
4
|
+
module Models
|
5
|
+
class LedgerEntry < Model
|
6
|
+
BOOL_FIELDS = []
|
7
|
+
FIELDS = {
|
8
|
+
:id => 0,
|
9
|
+
:currency => 1,
|
10
|
+
:mts => 3,
|
11
|
+
:amount => 5,
|
12
|
+
:balance => 6,
|
13
|
+
:description => 8,
|
14
|
+
:wallet => nil
|
15
|
+
}
|
16
|
+
|
17
|
+
FIELDS.each do |key, index|
|
18
|
+
attr_accessor key
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize (data)
|
22
|
+
super(data, FIELDS, BOOL_FIELDS)
|
23
|
+
|
24
|
+
spl = self.description.split('wallet')
|
25
|
+
self.wallet = (spl && spl[1]) ? spl[1].trim() : nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.unserialize (data)
|
29
|
+
return Model.unserialize(data, FIELDS, BOOL_FIELDS)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require_relative './model'
|
2
|
+
|
3
|
+
module Bitfinex
|
4
|
+
module Models
|
5
|
+
class MarginInfo < Model
|
6
|
+
attr_accessor :user_pl, :user_swaps, :margin_balance, :margin_net, :type
|
7
|
+
attr_accessor :symbol, :tradable_balance, :gross_balance, :buy, :sell
|
8
|
+
|
9
|
+
def initialize (data)
|
10
|
+
super(data, {}, [])
|
11
|
+
end
|
12
|
+
|
13
|
+
def serialize ()
|
14
|
+
if self.type == 'base'
|
15
|
+
return [
|
16
|
+
self.type,
|
17
|
+
[
|
18
|
+
self.user_pl,
|
19
|
+
self.user_swaps,
|
20
|
+
self.margin_balance,
|
21
|
+
self.margin_net
|
22
|
+
]
|
23
|
+
]
|
24
|
+
else
|
25
|
+
return [
|
26
|
+
self.type,
|
27
|
+
self.symbol,
|
28
|
+
[
|
29
|
+
self.tradable_balance,
|
30
|
+
self.gross_balance,
|
31
|
+
self.buy,
|
32
|
+
self.sell
|
33
|
+
]
|
34
|
+
]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.unserialize (arr)
|
39
|
+
type = arr[0]
|
40
|
+
|
41
|
+
if type == 'base'
|
42
|
+
payload = arr[1]
|
43
|
+
|
44
|
+
return {
|
45
|
+
:type => type,
|
46
|
+
:user_pl => payload[0],
|
47
|
+
:user_swaps => payload[1],
|
48
|
+
:margin_balance => payload[2],
|
49
|
+
:margin_net => payload[3]
|
50
|
+
}
|
51
|
+
else
|
52
|
+
symbol = arr[1]
|
53
|
+
payload = arr[2]
|
54
|
+
|
55
|
+
return {
|
56
|
+
:type => type,
|
57
|
+
:symbol => symbol,
|
58
|
+
:tradable_balance => payload[0],
|
59
|
+
:gross_balance => payload[1],
|
60
|
+
:buy => payload[2],
|
61
|
+
:sell => payload[3]
|
62
|
+
}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/models/model.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
module Bitfinex
|
2
|
+
module Models
|
3
|
+
class Model
|
4
|
+
def initialize (data, fields, boolFields)
|
5
|
+
@fields = fields
|
6
|
+
@boolFields = boolFields
|
7
|
+
|
8
|
+
if data.kind_of?(Array)
|
9
|
+
apply(self.class.unserialize(data))
|
10
|
+
elsif data.kind_of?(Hash)
|
11
|
+
apply(data)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def serialize
|
16
|
+
arr = []
|
17
|
+
|
18
|
+
@fields.each do |key, index|
|
19
|
+
return if index.nil?
|
20
|
+
|
21
|
+
if @boolFields.include?(key)
|
22
|
+
arr[index] = instance_variable_get("@#{key}") ? 1 : 0
|
23
|
+
else
|
24
|
+
arr[index] = instance_variable_get("@#{key}")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
arr
|
29
|
+
end
|
30
|
+
|
31
|
+
def apply (obj)
|
32
|
+
@fields.each do |key, index|
|
33
|
+
return if index.nil?
|
34
|
+
|
35
|
+
instance_variable_set("@#{key}", obj[key])
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.unserialize (data, fields, boolFields)
|
40
|
+
obj = {}
|
41
|
+
|
42
|
+
fields.each do |key, index|
|
43
|
+
return if index.nil?
|
44
|
+
|
45
|
+
if boolFields.include?(key)
|
46
|
+
obj[key] = data[index] == 1
|
47
|
+
else
|
48
|
+
obj[key] = data[index]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
return obj
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require_relative './model'
|
2
|
+
|
3
|
+
module Bitfinex
|
4
|
+
module Models
|
5
|
+
class Movement < Model
|
6
|
+
BOOL_FIELDS = []
|
7
|
+
FIELDS = {
|
8
|
+
:id => 0,
|
9
|
+
:currency => 1,
|
10
|
+
:currency_name => 2,
|
11
|
+
:mts_started => 5,
|
12
|
+
:mts_updated => 6,
|
13
|
+
:status => 9,
|
14
|
+
:amount => 12,
|
15
|
+
:fees => 13,
|
16
|
+
:destination_address => 16,
|
17
|
+
:transaction_id => 20
|
18
|
+
}
|
19
|
+
|
20
|
+
FIELDS.each do |key, index|
|
21
|
+
attr_accessor key
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize (data)
|
25
|
+
super(data, FIELDS, BOOL_FIELDS)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.unserialize (data)
|
29
|
+
return Model.unserialize(data, FIELDS, BOOL_FIELDS)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require_relative './model'
|
2
|
+
|
3
|
+
module Bitfinex
|
4
|
+
module Models
|
5
|
+
class Notification < Model
|
6
|
+
BOOL_FIELDS = []
|
7
|
+
FIELDS = {
|
8
|
+
:mts => 0,
|
9
|
+
:type => 1,
|
10
|
+
:message_id => 2,
|
11
|
+
:notify_info => 4,
|
12
|
+
:code => 5,
|
13
|
+
:status => 6,
|
14
|
+
:text => 7
|
15
|
+
}
|
16
|
+
|
17
|
+
FIELDS.each do |key, index|
|
18
|
+
attr_accessor key
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize (data)
|
22
|
+
super(data, FIELDS, BOOL_FIELDS)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.unserialize (data)
|
26
|
+
return Model.unserialize(data, FIELDS, BOOL_FIELDS)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/models/order.rb
ADDED
@@ -0,0 +1,197 @@
|
|
1
|
+
require 'bigdecimal'
|
2
|
+
require_relative './model'
|
3
|
+
|
4
|
+
module Bitfinex
|
5
|
+
module Models
|
6
|
+
class Order < Model
|
7
|
+
BOOL_FIELDS = []
|
8
|
+
FIELDS = {
|
9
|
+
:id => 0,
|
10
|
+
:gid => 1,
|
11
|
+
:cid => 2,
|
12
|
+
:symbol => 3,
|
13
|
+
:mts_create => 4,
|
14
|
+
:mts_update => 5,
|
15
|
+
:amount => 6,
|
16
|
+
:amount_orig => 7,
|
17
|
+
:type => 8,
|
18
|
+
:type_prev => 9,
|
19
|
+
:flags => 12,
|
20
|
+
:status => 13,
|
21
|
+
:price => 16,
|
22
|
+
:price_avg => 17,
|
23
|
+
:price_trailing => 18,
|
24
|
+
:price_aux_limit => 19,
|
25
|
+
:notify => 23,
|
26
|
+
:placed_id => 25
|
27
|
+
}
|
28
|
+
|
29
|
+
FLAG_OCO = 2 ** 14 # 16384
|
30
|
+
FLAG_POSTONLY = 2 ** 12 # 4096
|
31
|
+
FLAG_HIDDEN = 2 ** 6 # 64
|
32
|
+
FLAG_NO_VR = 2 ** 19 # 524288
|
33
|
+
FLAG_POS_CLOSE = 2 ** 9 # 512
|
34
|
+
FLAG_REDUCE_ONLY = 2 ** 10 # 1024
|
35
|
+
|
36
|
+
@@last_cid = Time.now.to_i
|
37
|
+
|
38
|
+
FIELDS.each do |key, index|
|
39
|
+
attr_accessor key
|
40
|
+
end
|
41
|
+
|
42
|
+
attr_accessor :last_amount, :meta
|
43
|
+
|
44
|
+
def self.gen_cid
|
45
|
+
@@last_cid += 1
|
46
|
+
@@last_cid
|
47
|
+
end
|
48
|
+
|
49
|
+
def initialize (data)
|
50
|
+
super(data, FIELDS, BOOL_FIELDS)
|
51
|
+
|
52
|
+
@flags = 0 unless @flags.is_a?(Numeric)
|
53
|
+
@amount_orig = @amount if @amount_orig.nil? && !@amount.nil?
|
54
|
+
@last_amount = @amount
|
55
|
+
|
56
|
+
if data.kind_of?(Hash)
|
57
|
+
set_oco(data[:oco]) if data.has_key?(:oco)
|
58
|
+
set_hidden(data[:hidden]) if data.has_key?(:hidden)
|
59
|
+
set_post_only(data[:post_only]) if data.has_key?(:post_only)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.unserialize (data)
|
64
|
+
return Model.unserialize(data, FIELDS, BOOL_FIELDS)
|
65
|
+
end
|
66
|
+
|
67
|
+
def modify_flag (flag, active)
|
68
|
+
return if (@flags & flag != 0) == active
|
69
|
+
|
70
|
+
@flags += active ? flag : -flag
|
71
|
+
end
|
72
|
+
|
73
|
+
def set_oco (v, stop_price = @price_aux_limit)
|
74
|
+
@price_aux_limit = stop_price if v
|
75
|
+
|
76
|
+
modify_flag(FLAG_OCO, v)
|
77
|
+
end
|
78
|
+
|
79
|
+
def set_hidden (v)
|
80
|
+
modify_flag(FLAG_HIDDEN, v)
|
81
|
+
end
|
82
|
+
|
83
|
+
def set_post_only (v)
|
84
|
+
modify_flag(FLAG_POSTONLY, v)
|
85
|
+
end
|
86
|
+
|
87
|
+
def set_no_variable_rates (v)
|
88
|
+
modify_flag(FLAG_NO_VR, v)
|
89
|
+
end
|
90
|
+
|
91
|
+
def set_position_close (v)
|
92
|
+
modify_flag(FLAG_POS_CLOSE, v)
|
93
|
+
end
|
94
|
+
|
95
|
+
def set_reduce_only (v)
|
96
|
+
modify_flag(FLAG_REDUCE_ONLY, v)
|
97
|
+
end
|
98
|
+
|
99
|
+
def is_oco
|
100
|
+
return !!(@flags & FLAG_OCO)
|
101
|
+
end
|
102
|
+
|
103
|
+
def is_hidden
|
104
|
+
return !!(@flags & FLAG_HIDDEN)
|
105
|
+
end
|
106
|
+
|
107
|
+
def is_post_only
|
108
|
+
return !!(@flags & FLAG_POSTONLY)
|
109
|
+
end
|
110
|
+
|
111
|
+
def includes_variable_rates
|
112
|
+
return !!(@flags & FLAG_NO_VR)
|
113
|
+
end
|
114
|
+
|
115
|
+
def is_position_close
|
116
|
+
return !!(@flags & FLAG_POS_CLOSE)
|
117
|
+
end
|
118
|
+
|
119
|
+
def is_reduce_only
|
120
|
+
return !!(@flags & FLAG_REDUCE_ONLY)
|
121
|
+
end
|
122
|
+
|
123
|
+
def get_last_fill_amount
|
124
|
+
@last_amount - @amount
|
125
|
+
end
|
126
|
+
|
127
|
+
def reset_fill_amount
|
128
|
+
@last_amount = @amount
|
129
|
+
end
|
130
|
+
|
131
|
+
def get_base_currency
|
132
|
+
@symbol[1...4]
|
133
|
+
end
|
134
|
+
|
135
|
+
def get_quote_currency
|
136
|
+
@symbol[4..-1]
|
137
|
+
end
|
138
|
+
|
139
|
+
def get_notional_value
|
140
|
+
(@amount * @price).abs
|
141
|
+
end
|
142
|
+
|
143
|
+
def is_partially_filled
|
144
|
+
a = @amount.abs
|
145
|
+
a > 0 && a < @amount_orig.abs
|
146
|
+
end
|
147
|
+
|
148
|
+
def to_new_order_packet
|
149
|
+
if !@cid.nil?
|
150
|
+
cid = @cid
|
151
|
+
else
|
152
|
+
cid = Order.gen_cid
|
153
|
+
end
|
154
|
+
|
155
|
+
data = {
|
156
|
+
:gid => @gid,
|
157
|
+
:cid => cid,
|
158
|
+
:symbol => @symbol,
|
159
|
+
:type => @type,
|
160
|
+
:amount => BigDecimal.new(@amount, 8).to_s,
|
161
|
+
:flags => @flags || 0,
|
162
|
+
:meta => @meta
|
163
|
+
}
|
164
|
+
|
165
|
+
data[:price] = BigDecimal.new(@price, 5).to_s if !@price.nil?
|
166
|
+
data[:price_trailing] = BigDecimal.new(@price_trailing, 5).to_s if !@price_trailing.nil?
|
167
|
+
|
168
|
+
if !@price_aux_limit.nil?
|
169
|
+
if is_oco
|
170
|
+
data[:price_oco_stop] = BigDecimal.new(@price_aux_limit, 5).to_s
|
171
|
+
else
|
172
|
+
data[:price_aux_limit] = BigDecimal.new(@price_aux_limit, 5).to_s
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
data
|
177
|
+
end
|
178
|
+
|
179
|
+
def update (changes = {})
|
180
|
+
changes.each do |k, v|
|
181
|
+
return if k == 'id'
|
182
|
+
|
183
|
+
if FIELDS.has_key?(k)
|
184
|
+
instance_variable_set(k, v)
|
185
|
+
elsif k == 'price_trailing'
|
186
|
+
@price_trailing = v.to_f
|
187
|
+
elsif k == 'price_oco_stop' || k == 'price_aux_limit'
|
188
|
+
@price_aux_limit = v.to_f
|
189
|
+
elsif k == 'delta' && v.is_a?(Numeric) && @amount.is_a?(Numeric)
|
190
|
+
@amount += v.to_f
|
191
|
+
@last_amount = @amount
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
@@ -0,0 +1,265 @@
|
|
1
|
+
require 'zlib'
|
2
|
+
|
3
|
+
module Bitfinex
|
4
|
+
module Models
|
5
|
+
class OrderBook
|
6
|
+
attr_reader :raw, :bids, :asks
|
7
|
+
|
8
|
+
def initialize (snap = [], raw = false)
|
9
|
+
@raw = raw
|
10
|
+
|
11
|
+
if snap.instance_of?(OrderBook)
|
12
|
+
@bids = snap.bids.dup
|
13
|
+
@asks = snap.asks.dup
|
14
|
+
elsif snap.kind_of?(Array)
|
15
|
+
update_from_snapshot(snap)
|
16
|
+
elsif snap.kind_of?(Hash)
|
17
|
+
@bids = snap[:bids].dup
|
18
|
+
@asks = snap[:asks].dup
|
19
|
+
else
|
20
|
+
@bids = []
|
21
|
+
@asks = []
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def update_from_snapshot (snap = [])
|
26
|
+
@bids = []
|
27
|
+
@asks = []
|
28
|
+
|
29
|
+
snap = [snap] if !snap[0].kind_of?(Array)
|
30
|
+
|
31
|
+
snap.each do |entry|
|
32
|
+
if entry.size == 4
|
33
|
+
if entry[3] < 0
|
34
|
+
@bids.push(entry)
|
35
|
+
else
|
36
|
+
@asks.push(entry)
|
37
|
+
end
|
38
|
+
else
|
39
|
+
if entry[2] < 0
|
40
|
+
@asks.push(entry)
|
41
|
+
else
|
42
|
+
@bids.push(entry)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
if self.raw
|
48
|
+
priceI = snap[0].size == 4 ? 2 : 1
|
49
|
+
else
|
50
|
+
priceI = 0
|
51
|
+
end
|
52
|
+
|
53
|
+
@bids.sort! { |a, b| b[priceI] <=> a[priceI]}
|
54
|
+
@asks.sort! { |a, b| a[priceI] <=> b[priceI]}
|
55
|
+
end
|
56
|
+
|
57
|
+
def top_bid_level
|
58
|
+
@bids[0] || nil
|
59
|
+
end
|
60
|
+
|
61
|
+
def top_bid
|
62
|
+
if self.raw
|
63
|
+
priceI = (@bids[0].size == 4 || @asks[0].size == 4) ? 2 : 1
|
64
|
+
else
|
65
|
+
priceI = 0
|
66
|
+
end
|
67
|
+
|
68
|
+
(top_bid_level || [])[priceI] || nil
|
69
|
+
end
|
70
|
+
|
71
|
+
def top_ask_level
|
72
|
+
@asks[0] || nil
|
73
|
+
end
|
74
|
+
|
75
|
+
def top_ask
|
76
|
+
if self.raw
|
77
|
+
priceI = (@bids[0].size == 4 || @asks[0].size == 4) ? 2 : 1
|
78
|
+
else
|
79
|
+
priceI = 0
|
80
|
+
end
|
81
|
+
|
82
|
+
(top_ask_level || [])[priceI] || nil
|
83
|
+
end
|
84
|
+
|
85
|
+
def mid_price
|
86
|
+
ask = top_ask || 0
|
87
|
+
bid = top_bid || 0
|
88
|
+
|
89
|
+
return bid if ask == 0
|
90
|
+
return ask if bid == 0
|
91
|
+
|
92
|
+
return (bid + ask) / 2
|
93
|
+
end
|
94
|
+
|
95
|
+
def spread
|
96
|
+
ask = top_ask || 0
|
97
|
+
bid = top_bid || 0
|
98
|
+
|
99
|
+
return 0 if ask == 0 || bid == 0
|
100
|
+
|
101
|
+
return ask - bid
|
102
|
+
end
|
103
|
+
|
104
|
+
def bid_amount
|
105
|
+
amount = 0
|
106
|
+
|
107
|
+
@bids.each do |entry|
|
108
|
+
amount += entry.size == 4 ? entry[3] : entry[2]
|
109
|
+
end
|
110
|
+
|
111
|
+
amount.abs
|
112
|
+
end
|
113
|
+
|
114
|
+
def ask_amount
|
115
|
+
amount = 0
|
116
|
+
|
117
|
+
@asks.each do |entry|
|
118
|
+
amount += entry.size == 4 ? entry[3] : entry[2]
|
119
|
+
end
|
120
|
+
|
121
|
+
amount.abs
|
122
|
+
end
|
123
|
+
|
124
|
+
def serialize
|
125
|
+
@asks + @bids
|
126
|
+
end
|
127
|
+
|
128
|
+
def checksum
|
129
|
+
data = []
|
130
|
+
|
131
|
+
for i in 0...25
|
132
|
+
bid = @bids[i]
|
133
|
+
ask = @asks[i]
|
134
|
+
|
135
|
+
if !bid.nil?
|
136
|
+
price = bid[0]
|
137
|
+
data.push(price)
|
138
|
+
data.push(bid.size == 4 ? bid[3] : bid[2])
|
139
|
+
end
|
140
|
+
|
141
|
+
if !ask.nil?
|
142
|
+
price = ask[0]
|
143
|
+
data.push(price)
|
144
|
+
data.push(ask.size == 4 ? ask[3] : ask[2])
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
[Zlib::crc32(data.join(':'))].pack("I").unpack("i")[0]
|
149
|
+
end
|
150
|
+
|
151
|
+
def update_with (entry)
|
152
|
+
if @raw
|
153
|
+
priceI = entry.size == 4 ? 2 : 1
|
154
|
+
count = -1
|
155
|
+
else
|
156
|
+
priceI = 0
|
157
|
+
count = entry.size == 4 ? entry[2] : entry[1]
|
158
|
+
end
|
159
|
+
|
160
|
+
price = entry[priceI]
|
161
|
+
oID = entry[0] # only for raw books
|
162
|
+
amount = entry.size == 4 ? entry[3] : entry[2]
|
163
|
+
|
164
|
+
if entry.size == 4
|
165
|
+
dir = amount < 0 ? 1 : -1
|
166
|
+
side = amount < 0 ? @bids : @asks
|
167
|
+
else
|
168
|
+
dir = amount < 0 ? -1 : 1
|
169
|
+
side = amount < 0 ? @asks : @bids
|
170
|
+
end
|
171
|
+
|
172
|
+
insertIndex = -1
|
173
|
+
|
174
|
+
# apply insert directly if empty
|
175
|
+
if (side.size == 0 && (@raw || count > 0))
|
176
|
+
side.push(entry)
|
177
|
+
return true
|
178
|
+
end
|
179
|
+
|
180
|
+
# match by price level, or order ID for raw books
|
181
|
+
side.each_with_index do |pl, i|
|
182
|
+
if (!@raw && pl[priceI] == price) || (@raw && pl[0] == oID)
|
183
|
+
if (!@raw && count == 0) || (@raw && price == 0)
|
184
|
+
side.slice!(i, 1)
|
185
|
+
return true
|
186
|
+
elsif !@raw || (@raw && price > 0)
|
187
|
+
side.slice!(i, 1)
|
188
|
+
break
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
if (@raw && price == 0) || (!@raw && count == 0)
|
194
|
+
return false
|
195
|
+
end
|
196
|
+
|
197
|
+
side.each_with_index do |pl, i|
|
198
|
+
if (insertIndex == -1 && (
|
199
|
+
(dir == -1 && price < pl[priceI]) || # by price
|
200
|
+
(dir == -1 && price == pl[priceI] && (raw && entry[0] < pl[0])) || # by order ID
|
201
|
+
(dir == 1 && price > pl[priceI]) ||
|
202
|
+
(dir == 1 && price == pl[priceI] && (raw && entry[0] < pl[0]))
|
203
|
+
))
|
204
|
+
insertIndex = i
|
205
|
+
break
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
# add
|
210
|
+
if (insertIndex == -1)
|
211
|
+
side.push(entry)
|
212
|
+
else
|
213
|
+
side.insert(insertIndex, entry)
|
214
|
+
end
|
215
|
+
|
216
|
+
return true
|
217
|
+
end
|
218
|
+
|
219
|
+
def self.unserialize (arr, raw = false)
|
220
|
+
if arr[0].kind_of?(Array)
|
221
|
+
entries = arr.map { |e| OrderBook.unserialize(e, raw) }
|
222
|
+
bids = entries.select { |e| (e[:rate] ? -e[:amount] : e[:amount]) > 0 }
|
223
|
+
asks = entries.select { |e| (e[:rate] ? -e[:amount] : e[:amount]) < 0 }
|
224
|
+
|
225
|
+
return {
|
226
|
+
:bids => bids,
|
227
|
+
:asks => asks
|
228
|
+
}
|
229
|
+
end
|
230
|
+
|
231
|
+
if arr.size == 4
|
232
|
+
if raw
|
233
|
+
return {
|
234
|
+
:order_id => arr[0],
|
235
|
+
:period => arr[1],
|
236
|
+
:rate => arr[2],
|
237
|
+
:amount => arr[3]
|
238
|
+
}
|
239
|
+
else
|
240
|
+
return {
|
241
|
+
:rate => arr[0],
|
242
|
+
:period => arr[1],
|
243
|
+
:count => arr[2],
|
244
|
+
:amount => arr[3]
|
245
|
+
}
|
246
|
+
end
|
247
|
+
else
|
248
|
+
if raw
|
249
|
+
return {
|
250
|
+
:order_id => arr[0],
|
251
|
+
:price => arr[1],
|
252
|
+
:amount => arr[2]
|
253
|
+
}
|
254
|
+
else
|
255
|
+
return {
|
256
|
+
:price => arr[0],
|
257
|
+
:count => arr[1],
|
258
|
+
:amount => arr[2]
|
259
|
+
}
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|