bitex_bot 0.9.0 → 0.9.1

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
  SHA1:
3
- metadata.gz: 8a52c57b2cb3f955ac849623421abc8296b1dc9c
4
- data.tar.gz: b1a88154cb71ef5868c510f9316f0e755b161c33
3
+ metadata.gz: 84beba74777fdc3e278589d5caf543ecba824116
4
+ data.tar.gz: 9dd73af6332116ece29196635b7b057114333781
5
5
  SHA512:
6
- metadata.gz: 1cb5d465e54e321a5d181aa86e988c0183938a70540ffcb5434000abf55627d9e8f875da413d67dd1cfa07892f0198c6be7d7c628d2e46a1a31caed5c6afa17d
7
- data.tar.gz: 8cef55c3f44533c9b43c7f82bede8a7fb2777e248ad533845a50ac6cc9006cf59bdb95499d94a5f8a6b509fa0a7bff46347d6020bb765f5cd503358a34512dea
6
+ metadata.gz: '0438c07f2f3f8111b9de9b66e5f942ef193f9036c9f8136739b77dc1933f2a73cf020e2f6a6fccf445e2450a5b98e163f1959871cab4a52bdc070c030fdd2b46'
7
+ data.tar.gz: 7296518d188e5ea3ac4e12128585b0f1701e08a76cd60405caa7c3833f92635783163aa3ed97a00fb58491a9fa9469d1caa73aafa934d616ca8bba15586f60fe
@@ -11,7 +11,7 @@ Metrics/LineLength:
11
11
  Max: 130
12
12
 
13
13
  Metrics/MethodLength:
14
- Max: 30
14
+ Max: 40
15
15
 
16
16
  Metrics/ParameterLists:
17
17
  Max: 7
@@ -62,6 +62,10 @@ class ApiWrapper
62
62
  :timestamp # Epoch Integer
63
63
  )
64
64
 
65
+ def name
66
+ self.class.name.underscore.split('_').first.capitalize
67
+ end
68
+
65
69
  # @return [Array<Transaction>]
66
70
  def transactions
67
71
  raise 'self subclass responsibility'
@@ -95,20 +99,27 @@ class ApiWrapper
95
99
  # @param type
96
100
  # @param price
97
101
  # @param quantity
102
+ # rubocop:disable Metrics/AbcSize
98
103
  def place_order(type, price, quantity)
99
104
  order = send_order(type, price, quantity)
100
105
  return order unless order.nil? || order.id.nil?
101
106
 
102
- BitexBot::Robot.log(:debug, "Captured error when placing order on #{self.class}")
107
+ BitexBot::Robot.log(:debug, "Captured error when placing order on #{name}")
103
108
  # Order may have gone through and be stuck somewhere in Wrapper's pipeline.
104
109
  # We just sleep for a bit and then look for the order.
105
- 20.times do
106
- BitexBot::Robot.sleep_for(10)
110
+ 5.times do |i|
111
+ BitexBot::Robot.log(
112
+ :info,
113
+ "#{name} cauldn't place #{type} order #{i} times for #{base.upcase} #{quantity} @ #{quote.upcase} #{price}.\n"\
114
+ "Going to sleep 10 seconds.\n"
115
+ )
116
+ BitexBot::Robot.sleep_for(15)
107
117
  order = find_lost(type, price, quantity)
108
118
  return order if order.present?
109
119
  end
110
- raise OrderNotFound, "Closing: #{type} order not found for #{quantity} #{base} @ #{quote} #{price}. #{order}"
120
+ raise OrderNotFound, "Closing: #{type} order not found for #{base.upcase} #{quantity} @ #{quote.upcase} #{price}."
111
121
  end
122
+ # rubocop:enable Metrics/AbcSize
112
123
 
113
124
  # Hook Method - arguments could not be used in their entirety by the subclasses
114
125
  def send_order(_type, _price, _quantity)
@@ -67,7 +67,8 @@ class BitexApiWrapper < ApiWrapper
67
67
  end
68
68
 
69
69
  def send_order(type, price, quantity, wait = false)
70
- { sell: Bitex::Ask, buy: Bitex::Bid }[type].create!(base_quote.to_sym, quantity, price, wait)
70
+ order = { sell: Bitex::Ask, buy: Bitex::Bid }[type].create!(base_quote.to_sym, quantity, price, wait)
71
+ order_parser(order) if order.present?
71
72
  end
72
73
 
73
74
  def transactions
@@ -44,11 +44,19 @@ class ItbitApiWrapper < ApiWrapper
44
44
  end
45
45
 
46
46
  def orders
47
- Itbit::Order.all(instrument: currency_pair, status: :open).map { |o| order_parser(o) }
47
+ Itbit::Order.all(instrument: currency_pair[:name], status: :open).map { |o| order_parser(o) }
48
48
  end
49
49
 
50
- def place_order(type, price, quantity)
51
- Itbit::Order.create!(type, currency_pair, quantity.round(4), price.round(2), wait: true, currency: currency_base)
50
+ def send_order(type, price, quantity)
51
+ order = Itbit::Order.create!(
52
+ type,
53
+ currency_pair[:name],
54
+ quantity.round(4),
55
+ price.round(2),
56
+ wait: true,
57
+ currency: currency_pair[:base]
58
+ )
59
+ order_parser(order) if order.present?
52
60
  rescue RestClient::RequestTimeout => e
53
61
  # On timeout errors, we still look for the latest active closing order that may be available.
54
62
  # We have a magic threshold of 5 minutes and also use the price to recognize an order as the current one.
@@ -32,7 +32,8 @@ class KrakenApiWrapper < ApiWrapper
32
32
  end
33
33
 
34
34
  def find_lost(type, price, quantity)
35
- KrakenOrder.find_lost(type, price, quantity)
35
+ order = KrakenOrder.find_lost(type, price, quantity)
36
+ order_parser(order) if order.present?
36
37
  end
37
38
 
38
39
  def order_book
@@ -42,11 +43,12 @@ class KrakenApiWrapper < ApiWrapper
42
43
  end
43
44
 
44
45
  def orders
45
- KrakenOrder.open.map { |ko| order_parser(ko) }
46
+ KrakenOrder.open.map { |o| order_parser(o) }
46
47
  end
47
48
 
48
49
  def send_order(type, price, quantity)
49
- KrakenOrder.create!(type, price, quantity)
50
+ order = KrakenOrder.create!(type, price, quantity)
51
+ order_parser(order) if order.present?
50
52
  end
51
53
 
52
54
  def transactions
@@ -65,8 +67,8 @@ class KrakenApiWrapper < ApiWrapper
65
67
  def balance_summary_parser(balances)
66
68
  open_orders = KrakenOrder.open
67
69
  BalanceSummary.new(
68
- balance_parser(balances, currency_pair[:base], btc_reserved(open_orders)),
69
- balance_parser(balances, currency_pair[:quote], usd_reserved(open_orders)),
70
+ balance_parser(balances, currency_pair[:base], crypto_reserved(open_orders)),
71
+ balance_parser(balances, currency_pair[:quote], fiat_reserved(open_orders)),
70
72
  client.private.trade_volume(pair: currency_pair[:altname])[:fees][currency_pair[:name]][:fee].to_d
71
73
  )
72
74
  end
@@ -76,12 +78,12 @@ class KrakenApiWrapper < ApiWrapper
76
78
  Balance.new(balances[currency].to_d, reserved, balances[currency].to_d - reserved)
77
79
  end
78
80
 
79
- def btc_reserved(open_orders)
80
- orders_by(open_orders, :sell).map { |o| (o.amount - o.executed_amount).to_d }.sum
81
+ def crypto_reserved(open_orders)
82
+ orders_by(open_orders, :sell).sum { |o| (o.amount - o.executed_amount).to_d }
81
83
  end
82
84
 
83
- def usd_reserved(open_orders)
84
- orders_by(open_orders, :buy).map { |o| (o.amount - o.executed_amount) * o.price.to_d }.sum
85
+ def fiat_reserved(open_orders)
86
+ orders_by(open_orders, :buy).sum { |o| (o.amount - o.executed_amount) * o.price.to_d }
85
87
  end
86
88
 
87
89
  def orders_by(open_orders, order_type)
@@ -100,9 +102,10 @@ class KrakenApiWrapper < ApiWrapper
100
102
  stock_market.map { |stock| OrderSummary.new(stock[0].to_d, stock[1].to_d) }
101
103
  end
102
104
 
103
- # <KrakenOrder: @id='O5TDV2-WDYB2-6OGJRD', @type=:buy, @price='1.01', @amount='1.00000000', @datetime='2013-09-26 23:15:04'>
105
+ # <KrakenOrder:0x007faf255382d0 @id="OGZ3HI-5I322-OIOV52", @type=:sell, @datetime=1546971756, @amount=0.248752e-2,
106
+ # @executed_amount=0.248752e-2, @price=0.40025e4, @avg_price=0.40074e4>
104
107
  def order_parser(order)
105
- Order.new(order.id.to_s, order.type, order.price, order.amount, order.datetime, order)
108
+ Order.new(order.id, order.type, order.price, order.amount, order.datetime, order)
106
109
  end
107
110
 
108
111
  # [
@@ -8,7 +8,9 @@ class KrakenOrder
8
8
  # rubocop:disable Metrics/AbcSize
9
9
  def self.create!(type, price, quantity)
10
10
  self.last_closed_order = closed.first.try(:id) || Time.now.to_i
11
- find(order_info_by(type, price.truncate(1), quantity.truncate(8))['txid'].first)
11
+ order = place_order(type, price.truncate(1), quantity.truncate(8))
12
+ order_id = order['txid'].first
13
+ find(order_id)
12
14
  rescue KrakenClient::ErrorResponse => e
13
15
  # Order could not be placed
14
16
  if e.message == 'EService:Unavailable'
@@ -23,9 +25,11 @@ class KrakenOrder
23
25
  end
24
26
  # rubocop:enable Metrics/AbcSize
25
27
 
26
- def self.order_info_by(type, price, quantity)
28
+ # <KrakenOrder:0x007faf255382d0 @id="OGZ3HI-5I322-OIOV52", @type=:sell, @datetime=1546971756, @amount=0.248752e-2,
29
+ # @executed_amount=0.248752e-2, @price=0.40025e4, @avg_price=0.40074e4>
30
+ def self.place_order(type, price, quantity)
27
31
  api_wrapper.client.private.add_order(
28
- pair: KrakenApiWrapper.currency_pair[:altname],
32
+ pair: api_wrapper.currency_pair[:altname],
29
33
  type: type,
30
34
  ordertype: 'limit',
31
35
  price: price,
@@ -39,6 +43,7 @@ class KrakenOrder
39
43
  retry
40
44
  end
41
45
 
46
+ # [BigDecimal, BigDecimal]
42
47
  def self.amount_and_quantity(order_id)
43
48
  order = find(order_id)
44
49
  amount = order.avg_price * order.executed_amount
@@ -61,12 +66,12 @@ class KrakenOrder
61
66
 
62
67
  def self.find_lost(type, price, quantity)
63
68
  BitexBot::Robot.log(:debug, "Looking for #{type} order in open orders...")
64
- order = open_order_by(type, price, quantity)
69
+ order = open_order_by(type, price.truncate(2), quantity.truncate(8))
65
70
  return log_and_return(order, :open) if order.present?
66
71
 
67
72
  BitexBot::Robot.log(:debug, "Looking for #{type} order in closed orders...")
68
- order = closed_order_by(type, price, quantity)
69
- return log_and_return(order, :closed) if order && order.id != last_closed_order
73
+ order = closed_order_by(type, price.truncate(2), quantity.truncate(8))
74
+ return log_and_return(order, :closed) if order.present? && order.id != last_closed_order
70
75
  end
71
76
 
72
77
  def self.log_and_return(order, status)
@@ -76,12 +81,12 @@ class KrakenOrder
76
81
 
77
82
  # description: [type, price, quantity]
78
83
  def self.open_order_by(type, price, quantity)
79
- open.detect { |o| o == [type, price, quantity] }
84
+ open.detect { |order| order == [type, price, quantity] }
80
85
  end
81
86
 
82
87
  # description: [type, price, quantity]
83
88
  def self.closed_order_by(type, price, quantity)
84
- closed(start: last_closed_order).detect { |o| o == [type, price, quantity] }
89
+ closed(start: last_closed_order).detect { |order| order == [type, price, quantity] }
85
90
  end
86
91
 
87
92
  # id: 'O5TDV2-WDYB2-6OGJRD'
@@ -102,5 +102,13 @@ module BitexBot
102
102
  def self.taker_specie_to_obtain
103
103
  Robot.taker.quote.upcase
104
104
  end
105
+
106
+ def self.maker_balance
107
+ store.maker_fiat
108
+ end
109
+
110
+ def self.available_maker_balance
111
+ Robot.maker.balance.fiat.available
112
+ end
105
113
  end
106
114
  end
@@ -8,6 +8,7 @@ module BitexBot
8
8
  cattr_reader(:close_time_to_live) { 30 }
9
9
 
10
10
  # Start a new CloseBuy that closes existing OpenBuy's by selling on another exchange what was just bought on bitex.
11
+ # rubocop:disable Metrics/AbcSize
11
12
  def self.close_open_positions
12
13
  return unless open_positions.any?
13
14
 
@@ -15,11 +16,18 @@ module BitexBot
15
16
  quantity = positions.sum(&:quantity)
16
17
  amount = positions.sum(&:amount) / fx_rate
17
18
  price = suggested_amount(positions) / quantity
18
-
19
- return unless Robot.taker.enough_order_size?(quantity, price)
19
+ unless Robot.taker.enough_order_size?(quantity, price)
20
+ Robot.log(
21
+ :info,
22
+ "Closing: #{Robot.taker.name} - enough order size for #{Robot.taker.base.upcase} #{quantity}"\
23
+ " @ #{Robot.taker.quote.upcase} #{price}"
24
+ )
25
+ return
26
+ end
20
27
 
21
28
  create_closing_flow!(price, quantity, amount, positions)
22
29
  end
30
+ # rubocop:enable Metrics/AbcSize
23
31
 
24
32
  def self.open_positions
25
33
  open_position_class.open
@@ -31,8 +39,13 @@ module BitexBot
31
39
  end
32
40
 
33
41
  def self.create_closing_flow!(price, quantity, amount, open_positions)
34
- create!(desired_price: price, quantity: quantity, amount: amount, open_positions: open_positions)
35
- .create_initial_order_and_close_position!
42
+ flow = create!(desired_price: price, quantity: quantity, amount: amount, open_positions: open_positions)
43
+ Robot.log(
44
+ :info,
45
+ "Closing: created #{self}##{flow.id}, desired price: #{flow.desired_price}, quantity: #{flow.quantity}, "\
46
+ "amount: #{flow.amount}."
47
+ )
48
+ flow.create_initial_order_and_close_position!
36
49
  nil
37
50
  end
38
51
  # end: close_open_positions helpers
@@ -105,7 +118,7 @@ module BitexBot
105
118
  Robot.log(
106
119
  :info,
107
120
  "Closing: Finished #{self.class} ##{id} earned"\
108
- "#{Robot.maker.quote.upcase} #{fiat_profit} and #{Robot.maker.base.upcase} #{crypto_profit}."
121
+ " #{Robot.maker.quote.upcase} #{fiat_profit} and #{Robot.maker.base.upcase} #{crypto_profit}."
109
122
  )
110
123
  end
111
124
  end
@@ -126,6 +139,7 @@ module BitexBot
126
139
 
127
140
  # This use hooks methods, these must be defined in the subclass:
128
141
  # order_type
142
+ # rubocop:disable Metrics/AbcSize
129
143
  def create_order_and_close_position(quantity, price)
130
144
  # TODO: investigate how to generate an ID to insert in the fields of goals where possible.
131
145
  Robot.log(
@@ -134,7 +148,14 @@ module BitexBot
134
148
  " #{Robot.taker.base.upcase} #{quantity} @ #{Robot.taker.quote.upcase} #{price}"
135
149
  )
136
150
  order = Robot.taker.place_order(order_type, price, quantity)
151
+ Robot.log(
152
+ :info,
153
+ "Closing: #{Robot.taker.name} placed #{order.type} with price: #{order.price} @ quantity #{order.amount}.\n"\
154
+ "Closing: Going to create Close#{order.type.to_s.capitalize} position.\n"
155
+ )
156
+
137
157
  close_positions.create!(order_id: order.id)
138
158
  end
159
+ # rubocop:enable Metrics/AbcSize
139
160
  end
140
161
  end
@@ -35,6 +35,12 @@ module BitexBot
35
35
  self.store = store
36
36
 
37
37
  remote_value, safest_price = calc_remote_value(maker_fee, taker_fee, taker_orders, taker_transactions)
38
+ Robot.log(
39
+ :info,
40
+ "Opening: Need #{taker_specie_to_spend} #{remote_value.truncate(8)} on #{Robot.taker.name} taker,"\
41
+ " has #{taker_balance.truncate(8)}."
42
+ )
43
+
38
44
  unless enough_remote_funds?(taker_balance, remote_value)
39
45
  raise CannotCreateFlow,
40
46
  "Needed #{remote_value} but you only have #{taker_specie_to_spend} #{taker_balance} on your taker market."
@@ -45,22 +51,26 @@ module BitexBot
45
51
  order = create_order!(price)
46
52
  unless enough_funds?(order)
47
53
  raise CannotCreateFlow,
48
- "You need to have #{maker_specie_to_spend} #{value_per_order} on Bitex to place this #{order_class}."
54
+ "Needed #{maker_specie_to_spend} #{value_per_order} on #{Robot.maker.name} maker to place this #{order_class}"\
55
+ " but you only have #{maker_specie_to_spend} #{available_maker_balance}."
49
56
  end
50
57
 
51
- Robot.log(
52
- :info,
53
- "Opening: Placed #{order_class} ##{order.id} #{value_per_order} @ #{Robot.maker.quote.upcase} #{price}"\
54
- " (#{maker_specie_to_obtain} #{remote_value})"
55
- )
56
-
57
- create!(
58
+ flow = create!(
58
59
  price: price,
59
60
  value_to_use: value_to_use,
60
61
  suggested_closing_price: safest_price,
61
62
  status: 'executing',
62
63
  order_id: order.id
63
64
  )
65
+
66
+ Robot.log(
67
+ :info,
68
+ "Opening: Placed #{order_class} ##{order.id} #{maker_specie_to_spend} #{value_per_order} @ #{price.truncate(2)}."\
69
+ " (#{maker_specie_to_obtain} #{remote_value})."\
70
+ " #{name.demodulize}##{flow.id} suggests closing price #{Robot.taker.quote.upcase}"\
71
+ " #{flow.suggested_closing_price}."
72
+ )
73
+ flow
64
74
  rescue StandardError => e
65
75
  raise CannotCreateFlow, e.message
66
76
  end
@@ -115,8 +125,8 @@ module BitexBot
115
125
  def self.create_open_position!(transaction, flow)
116
126
  Robot.log(
117
127
  :info,
118
- "Opening: #{name} ##{flow.id} was hit for #{transaction.raw.quantity} #{Robot.maker.base.upcase}"\
119
- " @ #{Robot.maker.quote.upcase} #{transaction.price}"
128
+ "Opening: #{self} ##{flow.id} was hit for #{Robot.maker.base.upcase} #{transaction.raw.quantity}"\
129
+ " @ #{Robot.maker.quote.upcase} #{transaction.price}. Creating #{open_position_class}..."
120
130
  )
121
131
 
122
132
  open_position_class.create!(
@@ -102,5 +102,13 @@ module BitexBot
102
102
  def self.taker_specie_to_obtain
103
103
  Robot.taker.base.upcase
104
104
  end
105
+
106
+ def self.maker_balance
107
+ store.maker_crypto
108
+ end
109
+
110
+ def self.available_maker_balance
111
+ Robot.maker.balance.crypto.available
112
+ end
105
113
  end
106
114
  end
@@ -71,7 +71,7 @@ module BitexBot
71
71
 
72
72
  def self.start_robot
73
73
  setup
74
- log(:info, 'Loading trading robot, ctrl+c *once* to exit gracefully.')
74
+ log(:info, "Loading trading robot, ctrl+c *once* to exit gracefully.\n")
75
75
  new
76
76
  end
77
77
 
@@ -84,19 +84,19 @@ module BitexBot
84
84
  sync_closing_flows if active_closing_flows?
85
85
  start_opening_flows_if_needed
86
86
  rescue CannotCreateFlow => e
87
- notify("#{e.message}:\n\n#{e.backtrace.join("\n")}")
87
+ notify("#{e.class} - #{e.message}\n\n#{e.backtrace.join("\n")}")
88
88
  sleep_for(60 * 3)
89
89
  rescue Curl::Err::TimeoutError => e
90
- log(:error, "#{e.class} - #{e.message}:\n\n#{e.backtrace.join("\n")}")
90
+ notify("#{e.class} - #{e.message}\n\n#{e.backtrace.join("\n")}")
91
91
  sleep_for(15)
92
92
  rescue OrderNotFound => e
93
- notify("#{e.class} - #{e.message}:\n\n#{e.backtrace.join("\n")}")
93
+ notify("#{e.class} - #{e.message}\n\n#{e.backtrace.join("\n")}")
94
94
  rescue ApiWrapperError => e
95
- notify("#{e.class} - #{e.message}:\n\n#{e.backtrace.join("\n")}")
95
+ notify("#{e.class} - #{e.message}\n\n#{e.backtrace.join("\n")}")
96
96
  rescue OrderArgumentError => e
97
- notify("#{e.class} - #{e.message}:\n\n#{e.backtrace.join("\n")}")
97
+ notify("#{e.class} - #{e.message}\n\n#{e.backtrace.join("\n")}")
98
98
  rescue StandardError => e
99
- notify("#{e.class} - #{e.message}:\n\n#{e.backtrace.join("\n")}")
99
+ notify("#{e.class} - #{e.message}\n\n#{e.backtrace.join("\n")}")
100
100
  sleep_for(60 * 2)
101
101
  end
102
102
  # rubocop:enable Metrics/AbcSize
@@ -168,7 +168,9 @@ module BitexBot
168
168
 
169
169
  maker_balance = with_cooldown { maker.balance }
170
170
  taker_balance = with_cooldown { taker.balance }
171
+
171
172
  sync_log_and_store(maker_balance, taker_balance)
173
+ log_balances('Store: Current balances.')
172
174
 
173
175
  check_balance_warning if expired_last_warning?
174
176
  return if stop_opening_flows?
@@ -188,6 +190,7 @@ module BitexBot
188
190
  end
189
191
 
190
192
  def sync_log_and_store(maker_balance, taker_balance)
193
+ log_balances('Store: Updating log, maker and taker balances...')
191
194
  file = Settings.log.try(:file)
192
195
  last_log = `tail -c 61440 #{file}` if file.present?
193
196
 
@@ -198,13 +201,24 @@ module BitexBot
198
201
  )
199
202
  end
200
203
 
204
+ # rubocop:disable Metrics/AbcSize
205
+ def log_balances(header)
206
+ log(
207
+ :info,
208
+ "#{header}\n"\
209
+ "Store: #{maker.name} maker - #{maker.base.upcase}: #{store.maker_crypto}, #{maker.quote.upcase}: #{store.maker_fiat}.\n"\
210
+ "Store: #{taker.name} taker - #{taker.base.upcase}: #{store.taker_crypto}, #{taker.quote.upcase}: #{store.taker_fiat}.\n"
211
+ )
212
+ end
213
+ # rubocop:enable Metrics/AbcSize
214
+
201
215
  def expired_last_warning?
202
216
  store.last_warning.nil? || store.last_warning < 30.minutes.ago
203
217
  end
204
218
 
205
219
  def stop_opening_flows?
206
- (log(:debug, "Not placing new orders, #{maker.quote.upcase} target not met") if alert?(:fiat, :stop)) ||
207
- (log(:debug, "Not placing new orders, #{maker.base.upcase} target not met") if alert?(:crypto, :stop))
220
+ (log(:info, "Opening: Not placing new orders, #{maker.quote.upcase} target not met") if alert?(:fiat, :stop)) ||
221
+ (log(:info, "Opening: Not placing new orders, #{maker.base.upcase} target not met") if alert?(:crypto, :stop))
208
222
  end
209
223
 
210
224
  def check_balance_warning
@@ -229,7 +243,7 @@ module BitexBot
229
243
  end
230
244
 
231
245
  def notify(message, subj = 'Notice from your robot trader')
232
- log(:error, message)
246
+ log(:info, "Sending mail with subject: #{subj}\n\n#{message}")
233
247
  return unless Settings.mailer.present?
234
248
 
235
249
  new_mail(subj, message).tap do |mail|
@@ -1,3 +1,3 @@
1
1
  module BitexBot
2
- VERSION = '0.9.0'.freeze
2
+ VERSION = '0.9.1'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bitex_bot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nubis
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-01-04 00:00:00.000000000 Z
12
+ date: 2019-01-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord