rbtc_arbitrage_simple 1.4.4 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +16 -14
  3. data/Gemfile.lock +17 -21
  4. data/lib/rbtc_arbitrage.rb +3 -1
  5. data/lib/rbtc_arbitrage/campbx.rb +3 -4
  6. data/lib/rbtc_arbitrage/cli.rb +2 -2
  7. data/lib/rbtc_arbitrage/clients/coinbase_client.rb +3 -2
  8. data/lib/rbtc_arbitrage/trader.rb +21 -75
  9. data/lib/rbtc_arbitrage/trader/logger.rb +31 -0
  10. data/lib/rbtc_arbitrage/trader/notifier.rb +60 -0
  11. data/lib/rbtc_arbitrage/version.rb +1 -1
  12. data/rbtc_arbitrage.gemspec +1 -1
  13. data/spec/clients/coinbase_client_spec.rb +2 -3
  14. data/spec/rbtc_arbitrage_spec.rb +1 -1
  15. data/spec/spec_helper.rb +2 -1
  16. data/spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/should_raise_SecurityError_if_not_live.yml +30 -25
  17. data/spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/when_live/raises_SecurityError_if_not_enough_BTC.yml +38 -24
  18. data/spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/when_live/raises_SecurityError_if_not_enough_USD.yml +40 -26
  19. data/spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/when_live/should_fetch_balance.yml +30 -25
  20. data/spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/when_live/shouldn_t_raise_security_error.yml +72 -53
  21. data/spec/support/cassettes/RbtcArbitrage_Trader/_fetch_prices/gets_the_right_price_set.yml +60 -50
  22. data/spec/trader_spec.rb +8 -8
  23. metadata +10 -19
  24. data/lib/rbtc_arbitrage/clients/mtgox_client.rb +0 -56
  25. data/spec/clients/mtgox_client_spec.rb +0 -53
  26. data/spec/support/cassettes/RbtcArbitrage_Clients_MtGoxClient/_balance/fetches_the_balance_correctly.yml +0 -77
  27. data/spec/support/cassettes/RbtcArbitrage_Clients_MtGoxClient/_price/fetches_price_for_buy_correctly.yml +0 -44
  28. data/spec/support/cassettes/RbtcArbitrage_Clients_MtGoxClient/_price/fetches_price_for_sell_correctly.yml +0 -44
  29. data/spec/support/cassettes/RbtcArbitrage_Clients_MtGoxClient/_price/fetches_prices_correctly.yml +0 -85
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ef0a86fb8de589d7b45bc44e07ce93222bad2e17
4
- data.tar.gz: b78c0c931af1ff282bba897320eb59c0b5279615
3
+ metadata.gz: f4cfee1b5de308aa0ec6007b8173a7220b4d4501
4
+ data.tar.gz: b67691a517aa55e2d8fe337f493acc172de76f68
5
5
  SHA512:
6
- metadata.gz: ff3874ce7ee3bdecf7b30e8338d2472fe33371f1a62ecb135e1dfcbcb04e1342828415907990aba602262450a59096e0fc4f34447ac65930269d116f7e73e826
7
- data.tar.gz: 77c3cdb383df68cd78e3facc9122f7001e55fd0179b1aca441abd5a286e2b771c2a731ed66a5e6c7c7708c7c406cbba1608bd80640462f212bc7a3d21478f167
6
+ metadata.gz: 827f92b92f8728f3802e0a8c341d5f2d0958a3b659841934cd1c15f790ea5dd9ddc1130831af239fa44d1f9e6b06564e680c922894cb12f9a60f2ef69e269aaa
7
+ data.tar.gz: 303826e5db0cf919370ed927c60930747b99b6d00962d18547a465743a819c8b38d72907d532f22ff783dc1e88c4b66fdcc8f8e4bb03c1147f246c2fbdd36557
data/Gemfile CHANGED
@@ -2,17 +2,19 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in rbtc_arbitrage.gemspec
4
4
  gemspec
5
- gem 'rspec'
6
- gem "activemodel", ">= 3.1"
7
- gem "activesupport", ">= 3.1"
8
- gem 'guard'
9
- gem 'ruby_gntp'
10
- # gem 'awesome_print'
11
- gem 'guard-rspec'
12
- gem 'simplecov'
13
- gem 'coveralls', require: false
14
- gem "webmock"
15
- gem 'vcr'
16
- gem 'codeclimate-test-reporter'
17
- gem 'hashie'
18
- gem 'sinatra'
5
+ group :development do
6
+ gem 'rspec'
7
+ gem "activemodel", ">= 3.1"
8
+ gem "activesupport", ">= 3.1"
9
+ gem 'guard'
10
+ gem 'ruby_gntp'
11
+ # gem 'awesome_print'
12
+ gem 'guard-rspec'
13
+ gem 'simplecov'
14
+ gem 'coveralls', require: false
15
+ gem "webmock"
16
+ gem 'vcr'
17
+ gem 'codeclimate-test-reporter'
18
+ gem 'hashie'
19
+ gem 'sinatra'
20
+ end
data/Gemfile.lock CHANGED
@@ -1,29 +1,29 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rbtc_arbitrage_simple (1.4.4)
4
+ rbtc_arbitrage_simple (2.0.1)
5
5
  activemodel (>= 3.1)
6
6
  activesupport (>= 3.1)
7
7
  btce (= 0.2.4)
8
8
  coinbase (= 1.2.6)
9
- mtgox
9
+ faraday (= 0.8.8)
10
10
  pony
11
11
  thor
12
12
 
13
13
  GEM
14
14
  remote: https://rubygems.org/
15
15
  specs:
16
- activemodel (4.0.2)
17
- activesupport (= 4.0.2)
16
+ activemodel (4.0.4)
17
+ activesupport (= 4.0.4)
18
18
  builder (~> 3.1.0)
19
- activesupport (4.0.2)
20
- i18n (~> 0.6, >= 0.6.4)
19
+ activesupport (4.0.4)
20
+ i18n (~> 0.6, >= 0.6.9)
21
21
  minitest (~> 4.2)
22
22
  multi_json (~> 1.3)
23
23
  thread_safe (~> 0.1)
24
24
  tzinfo (~> 0.3.37)
25
25
  addressable (2.3.5)
26
- atomic (1.1.14)
26
+ atomic (1.1.16)
27
27
  btce (0.2.4)
28
28
  monkey-patch
29
29
  builder (3.1.4)
@@ -61,7 +61,7 @@ GEM
61
61
  guard (>= 2.1.1)
62
62
  rspec (~> 3.0.0.beta, >= 2.14, < 4.0)
63
63
  hashie (2.0.5)
64
- httparty (0.12.0)
64
+ httparty (0.13.0)
65
65
  json (~> 1.8)
66
66
  multi_xml (>= 0.5.2)
67
67
  i18n (0.6.9)
@@ -80,16 +80,13 @@ GEM
80
80
  minitest (4.7.5)
81
81
  money (5.1.1)
82
82
  i18n (~> 0.6.0)
83
- monkey-patch (0.0.14)
83
+ monkey-patch (0.0.16)
84
84
  activesupport
85
- mtgox (1.1.0)
86
- faraday (~> 0.8, < 0.10)
87
- json (~> 1.7, >= 1.7.7)
88
- multi_json (1.8.2)
85
+ multi_json (1.9.2)
89
86
  multi_xml (0.5.5)
90
87
  multipart-post (1.2.0)
91
- polyglot (0.3.3)
92
- pony (1.6.2)
88
+ polyglot (0.3.4)
89
+ pony (1.8)
93
90
  mail (>= 2.0)
94
91
  pry (0.9.12.4)
95
92
  coderay (~> 1.0)
@@ -131,15 +128,14 @@ GEM
131
128
  term-ansicolor (1.2.2)
132
129
  tins (~> 0.8)
133
130
  thor (0.18.1)
134
- thread_safe (0.1.3)
135
- atomic
131
+ thread_safe (0.3.1)
132
+ atomic (>= 1.1.7, < 2)
136
133
  tilt (1.4.1)
137
134
  timers (1.1.0)
138
135
  tins (0.13.1)
139
- treetop (1.4.15)
140
- polyglot
141
- polyglot (>= 0.3.1)
142
- tzinfo (0.3.38)
136
+ treetop (1.5.3)
137
+ polyglot (~> 0.3)
138
+ tzinfo (0.3.39)
143
139
  vcr (2.8.0)
144
140
  webmock (1.16.1)
145
141
  addressable (>= 2.2.7)
@@ -1,10 +1,12 @@
1
+ require 'bundler'
2
+ Bundler.require(:default)
1
3
  require 'thor'
2
- require 'mtgox'
3
4
  require_relative 'rbtc_arbitrage/campbx.rb'
4
5
  require 'btce'
5
6
  require 'coinbase'
6
7
  require 'pony'
7
8
  require_relative 'rbtc_arbitrage/client.rb'
9
+ Dir["#{File.dirname(__FILE__)}/rbtc_arbitrage/trader/*.rb"].each { |f| require(f) }
8
10
  Dir["#{File.dirname(__FILE__)}/rbtc_arbitrage/**/*.rb"].each { |f| require(f) }
9
11
 
10
12
  module RbtcArbitrage
@@ -70,10 +70,10 @@ module CampBX
70
70
  request.set_form_data( post_data )
71
71
  end
72
72
 
73
- # debug # need to test w/valid credentials
74
- #puts "Sending request to #{uri}"
75
- #puts "Post Data: #{post_data}"
73
+ make_request(http, request)
74
+ end
76
75
 
76
+ def make_request http, request
77
77
  # CampBX API: max 1 request per 500ms
78
78
  delta = Time.now - @@last
79
79
  #puts delta*1000
@@ -90,7 +90,6 @@ module CampBX
90
90
  else # HTTP ERROR
91
91
  warn "HTTP Error: + #{res.code}"
92
92
  end
93
-
94
93
  end
95
94
 
96
95
  end
@@ -6,8 +6,8 @@ module RbtcArbitrage
6
6
  option :cutoff, type: :numeric, default: 2, desc: "The minimum profit level required to execute a trade."
7
7
  option :volume, type: :numeric, default: 0.01, desc: "The amount of bitcoins to trade per transaction."
8
8
  option :verbose, type: :boolean, default: true, desc: "Whether you wish to log information."
9
- option :buyer, type: :string, default: "campbx"
10
- option :seller, type: :string, default: "mtgox"
9
+ option :buyer, type: :string, default: "btce"
10
+ option :seller, type: :string, default: "campbx"
11
11
  option :repeat, type: :numeric, default: nil
12
12
  option :notify, type: :boolean, default: false
13
13
  def trade
@@ -16,10 +16,11 @@ module RbtcArbitrage
16
16
  if @options[:verbose]
17
17
  warning = "Coinbase doesn't provide a USD balance because"
18
18
  warning << " it connects to your bank account. Be careful, "
19
- warning << "because this will withdraw directly from your accounts."
19
+ warning << "because this will withdraw directly from your accounts"
20
+ warning << "when you trade live."
20
21
  logger.warn warning
21
22
  end
22
- @balance ||= [interface.balance.to_f, max_float]
23
+ @balance ||= [max_float, max_float]
23
24
  end
24
25
 
25
26
  # Configures the client's API keys.
@@ -1,5 +1,8 @@
1
1
  module RbtcArbitrage
2
2
  class Trader
3
+ include RbtcArbitrage::TraderHelpers::Notifier
4
+ include RbtcArbitrage::TraderHelpers::Logger
5
+
3
6
  attr_reader :buy_client, :sell_client, :received
4
7
  attr_accessor :buyer, :seller, :options
5
8
 
@@ -19,10 +22,10 @@ module RbtcArbitrage
19
22
  set_key opts, :verbose, true
20
23
  set_key opts, :live, false
21
24
  set_key opts, :repeat, nil
22
- exchange = opts[:buyer] || :campbx
25
+ exchange = opts[:buyer] || :btce
23
26
  set_key opts, :notify, false
24
27
  @buy_client = client_for_exchange(exchange)
25
- exchange = opts[:seller] || :mtgox
28
+ exchange = opts[:seller] || :campbx
26
29
  @sell_client = client_for_exchange(exchange)
27
30
  self
28
31
  end
@@ -64,14 +67,7 @@ module RbtcArbitrage
64
67
  raise SecurityError, "--live flag is false. Not executing trade." unless options[:live]
65
68
  get_balance
66
69
  if @percent > @options[:cutoff]
67
- if @paid > buyer[:usd] || @options[:volume] > seller[:btc]
68
- raise SecurityError, "Not enough funds. Exiting."
69
- else
70
- logger.info "Trading live!" if options[:verbose]
71
- @buy_client.buy
72
- @sell_client.sell
73
- @buy_client.transfer @sell_client
74
- end
70
+ buy_and_transfer!
75
71
  else
76
72
  logger.info "Not trading live because cutoff is higher than profit." if @options[:verbose]
77
73
  end
@@ -82,19 +78,8 @@ module RbtcArbitrage
82
78
  buyer[:price] = @buy_client.price(:buy)
83
79
  seller[:price] = @sell_client.price(:sell)
84
80
  prices = [buyer[:price], seller[:price]]
85
- @paid = buyer[:price] * 1.006 * @options[:volume]
86
- @received = seller[:price] * 0.994 * @options[:volume]
87
- @percent = ((received/@paid - 1) * 100).round(2)
88
- end
89
81
 
90
- def log_info
91
- lower_ex = @buy_client.exchange.to_s.capitalize
92
- higher_ex = @sell_client.exchange.to_s.capitalize
93
- logger.info "#{lower_ex}: $#{buyer[:price].round(2)}"
94
- logger.info "#{higher_ex}: $#{seller[:price].round(2)}"
95
- logger.info "buying #{@options[:volume]} btc from #{lower_ex} for $#{@paid.round(2)}"
96
- logger.info "selling #{@options[:volume]} btc on #{higher_ex} for $#{@received.round(2)}"
97
- logger.info "profit: $#{(@received - @paid).round(2)} (#{@percent.round(2)}%)"
82
+ calculate_profit
98
83
  end
99
84
 
100
85
  def get_balance
@@ -102,10 +87,6 @@ module RbtcArbitrage
102
87
  @buyer[:btc], @buyer[:usd] = @buy_client.balance
103
88
  end
104
89
 
105
- def logger
106
- @options[:logger]
107
- end
108
-
109
90
  def validate_env
110
91
  [@sell_client, @buy_client].each do |client|
111
92
  client.validate_env
@@ -135,59 +116,24 @@ module RbtcArbitrage
135
116
  end
136
117
  end
137
118
 
138
- def notify
139
- return false unless options[:notify]
140
- return false unless @percent > options[:cutoff]
141
- setup_pony
119
+ private
142
120
 
143
- options[:logger].info "Sending email to #{ENV['SENDGRID_EMAIL']}"
144
- Pony.mail({
145
- body: notification,
146
- to: ENV['SENDGRID_EMAIL'],
147
- })
121
+ def calculate_profit
122
+ @paid = buyer[:price] * 1.006 * @options[:volume]
123
+ @received = seller[:price] * 0.994 * @options[:volume]
124
+ @percent = ((received/@paid - 1) * 100).round(2)
148
125
  end
149
126
 
150
- def setup_pony
151
- Pony.options = {
152
- from: ENV['FROM_EMAIL'] || "info@example.org",
153
- subject: "rbtc_arbitrage notification",
154
- via: :smtp,
155
- via_options: {
156
- address: 'smtp.sendgrid.net',
157
- port: '587',
158
- domain: 'heroku.com',
159
- user_name: ENV['SENDGRID_USERNAME'],
160
- password: ENV['SENDGRID_PASSWORD'],
161
- authentication: :plain,
162
- enable_starttls_auto: true
163
- }
164
- }
127
+ def buy_and_transfer!
128
+ if @paid > buyer[:usd] || @options[:volume] > seller[:btc]
129
+ raise SecurityError, "Not enough funds. Exiting."
130
+ else
131
+ logger.info "Trading live!" if options[:verbose]
132
+ @buy_client.buy
133
+ @sell_client.sell
134
+ @buy_client.transfer @sell_client
135
+ end
165
136
  end
166
137
 
167
- def notification
168
- lower_ex = @buy_client.exchange.to_s.capitalize
169
- higher_ex = @sell_client.exchange.to_s.capitalize
170
- <<-eos
171
- Update from your friendly rbtc_arbitrage trader:
172
-
173
- -------------------
174
-
175
- #{lower_ex}: $#{buyer[:price].round(2)}
176
- #{higher_ex}: $#{seller[:price].round(2)}
177
- buying #{@options[:volume]} btc from #{lower_ex} for $#{@paid.round(2)}
178
- selling #{@options[:volume]} btc on #{higher_ex} for $#{@received.round(2)}
179
- profit: $#{(@received - @paid).round(2)} (#{@percent.round(2)}%)
180
-
181
- -------------------
182
-
183
- options:
184
-
185
- #{options.reject{|k,v| v.is_a?(Logger)}.collect{|k,v| "#{k}: #{v.to_s}"}.join(" | ")}
186
-
187
- -------------------
188
-
189
- https://github.com/hstove/rbtc_arbitrage
190
- eos
191
- end
192
138
  end
193
139
  end
@@ -0,0 +1,31 @@
1
+ module RbtcArbitrage
2
+ module TraderHelpers
3
+ module Logger
4
+ def logger
5
+ @options[:logger]
6
+ end
7
+
8
+ def log_info
9
+ lower_ex = @buy_client.exchange.to_s.capitalize
10
+ higher_ex = @sell_client.exchange.to_s.capitalize
11
+ logger.info "#{lower_ex}: $#{buyer[:price].round(2)}"
12
+ logger.info "#{higher_ex}: $#{seller[:price].round(2)}"
13
+ logger.info "buying #{@options[:volume]} btc from #{lower_ex} for $#{@paid.round(2)}"
14
+ logger.info "selling #{@options[:volume]} btc on #{higher_ex} for $#{@received.round(2)}"
15
+
16
+ log_profit
17
+ end
18
+
19
+ private
20
+
21
+ def log_profit
22
+ profit_msg = "profit: $#{(@received - @paid).round(2)} (#{@percent.round(2)}%)"
23
+ if cutoff = @options[:cutoff]
24
+ profit_msg << " is #{@percent < cutoff ? 'below' : 'above'} cutoff"
25
+ profit_msg << " of #{cutoff}%."
26
+ end
27
+ logger.info profit_msg
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,60 @@
1
+ module RbtcArbitrage
2
+ module TraderHelpers
3
+ module Notifier
4
+ def notify
5
+ return false unless options[:notify]
6
+ return false unless @percent > options[:cutoff]
7
+ setup_pony
8
+
9
+ options[:logger].info "Sending email to #{ENV['SENDGRID_EMAIL']}"
10
+ Pony.mail({
11
+ body: notification,
12
+ to: ENV['SENDGRID_EMAIL'],
13
+ })
14
+ end
15
+
16
+ def setup_pony
17
+ Pony.options = {
18
+ from: ENV['FROM_EMAIL'] || "info@example.org",
19
+ subject: "rbtc_arbitrage notification",
20
+ via: :smtp,
21
+ via_options: {
22
+ address: 'smtp.sendgrid.net',
23
+ port: '587',
24
+ domain: 'heroku.com',
25
+ user_name: ENV['SENDGRID_USERNAME'],
26
+ password: ENV['SENDGRID_PASSWORD'],
27
+ authentication: :plain,
28
+ enable_starttls_auto: true
29
+ }
30
+ }
31
+ end
32
+
33
+ def notification
34
+ lower_ex = @buy_client.exchange.to_s.capitalize
35
+ higher_ex = @sell_client.exchange.to_s.capitalize
36
+ <<-eos
37
+ Update from your friendly rbtc_arbitrage trader:
38
+
39
+ -------------------
40
+
41
+ #{lower_ex}: $#{buyer[:price].round(2)}
42
+ #{higher_ex}: $#{seller[:price].round(2)}
43
+ buying #{@options[:volume]} btc from #{lower_ex} for $#{@paid.round(2)}
44
+ selling #{@options[:volume]} btc on #{higher_ex} for $#{@received.round(2)}
45
+ profit: $#{(@received - @paid).round(2)} (#{@percent.round(2)}%)
46
+
47
+ -------------------
48
+
49
+ options:
50
+
51
+ #{options.reject{|k,v| v.is_a?(Logger)}.collect{|k,v| "#{k}: #{v.to_s}"}.join(" | ")}
52
+
53
+ -------------------
54
+
55
+ https://github.com/hstove/rbtc_arbitrage
56
+ eos
57
+ end
58
+ end
59
+ end
60
+ end
@@ -1,3 +1,3 @@
1
1
  module RbtcArbitrage
2
- VERSION = "1.4.4"
2
+ VERSION = "2.0.1"
3
3
  end
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
21
21
  spec.add_development_dependency "bundler", "~> 1.3"
22
22
  spec.add_development_dependency "rake"
23
23
 
24
- spec.add_dependency "mtgox"
24
+ spec.add_dependency "faraday", "0.8.8"
25
25
  spec.add_dependency "activemodel", ">= 3.1"
26
26
  spec.add_dependency "activesupport", ">= 3.1"
27
27
  spec.add_dependency "thor"