rbtc_arbitrage 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.
Files changed (38) hide show
  1. checksums.yaml +6 -6
  2. data/.rspec +1 -1
  3. data/.travis.yml +13 -3
  4. data/Gemfile +10 -0
  5. data/Guardfile +8 -0
  6. data/README.md +41 -3
  7. data/btce-api-key.yml +2 -0
  8. data/lib/rbtc_arbitrage/campbx.rb +98 -0
  9. data/lib/rbtc_arbitrage/cli.rb +3 -1
  10. data/lib/rbtc_arbitrage/client.rb +45 -0
  11. data/lib/rbtc_arbitrage/clients/bitstamp_client.rb +52 -0
  12. data/lib/rbtc_arbitrage/clients/mtgox_client.rb +45 -0
  13. data/lib/rbtc_arbitrage/trader.rb +62 -66
  14. data/lib/rbtc_arbitrage/version.rb +1 -1
  15. data/lib/rbtc_arbitrage.rb +3 -1
  16. data/rbtc_arbitrage.gemspec +2 -0
  17. data/spec/cli_spec.rb +8 -0
  18. data/spec/client_spec.rb +18 -0
  19. data/spec/clients/bitstamp_client_spec.rb +53 -0
  20. data/spec/clients/mtgox_client_spec.rb +52 -0
  21. data/spec/spec_helper.rb +27 -12
  22. data/spec/support/cassettes/RbtcArbitrage_Clients_BitstampClient/_balance/fetches_the_balance_correctly.yml +96 -0
  23. data/spec/support/cassettes/RbtcArbitrage_Clients_BitstampClient/_price/fetches_price_for_buy_correctly.yml +52 -0
  24. data/spec/support/cassettes/RbtcArbitrage_Clients_BitstampClient/_price/fetches_price_for_sell_correctly.yml +52 -0
  25. data/spec/support/cassettes/RbtcArbitrage_Clients_BitstampClient/_price/fetches_prices_correctly.yml +44 -0
  26. data/spec/support/cassettes/RbtcArbitrage_Clients_MtGoxClient/_balance/fetches_the_balance_correctly.yml +77 -0
  27. data/spec/support/cassettes/RbtcArbitrage_Clients_MtGoxClient/_price/fetches_price_for_buy_correctly.yml +44 -0
  28. data/spec/support/cassettes/RbtcArbitrage_Clients_MtGoxClient/_price/fetches_price_for_sell_correctly.yml +44 -0
  29. data/spec/support/cassettes/RbtcArbitrage_Clients_MtGoxClient/_price/fetches_prices_correctly.yml +85 -0
  30. data/spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/should_raise_SecurityError_if_not_live.yml +93 -0
  31. data/spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/when_live/raises_SecurityError_if_not_enough_BTC.yml +86 -0
  32. data/spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/when_live/raises_SecurityError_if_not_enough_USD.yml +80 -0
  33. data/spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/when_live/should_fetch_balance.yml +225 -0
  34. data/spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/when_live/shouldn_t_raise_security_error.yml +262 -0
  35. data/spec/support/cassettes/RbtcArbitrage_Trader/_fetch_prices/gets_the_right_price_set.yml +176 -0
  36. data/spec/support/cassettes/RbtcArbitrage_Trader/_get_balance/fetches_the_right_balance.yml +166 -0
  37. data/spec/trader_spec.rb +156 -19
  38. metadata +89 -18
data/spec/trader_spec.rb CHANGED
@@ -1,40 +1,177 @@
1
1
  require 'spec_helper'
2
2
  describe RbtcArbitrage::Trader do
3
- before :each do
4
- @trader = RbtcArbitrage::Trader.new
3
+ let(:trader) { RbtcArbitrage::Trader.new(verbose: false) }
4
+ describe "#validate_env" do
5
5
 
6
- #clear env variables
7
- ["KEY", "SECRET", "ADDRESS"].each do |suffix|
8
- ["MTGOX", "BITSTAMP"].each do |prefix|
9
- key = "#{prefix}_#{suffix}"
10
- ENV[key] = nil
6
+ before :each do
7
+ @old_keys = {}
8
+ #clear env variables
9
+ ["KEY", "SECRET", "ADDRESS"].each do |suffix|
10
+ ["MTGOX", "BITSTAMP"].each do |prefix|
11
+ key = "#{prefix}_#{suffix}"
12
+ @old_keys[key] = ENV[key]
13
+ ENV[key] = nil
14
+ end
15
+ end
16
+ end
17
+
18
+ after :each do
19
+ @old_keys ||= {}
20
+ @old_keys.each do |k,v|
21
+ ENV[k] = v
11
22
  end
12
23
  end
13
- end
14
24
 
15
- describe "#validate_env" do
16
25
  it "should raise errors when missing env variable" do
17
26
  ["KEY", "SECRET", "ADDRESS"].each do |suffix|
18
- ["MTGOX", "BITSTAMP"].each do |prefix|
19
- key = "#{prefix}_#{suffix}"
20
- expect { @trader.validate_env }.to raise_error(ArgumentError, "Exiting because missing required ENV variable $#{key}.")
21
- ENV[key] = "some value"
22
- end
27
+ key = "#{trader.sell_client.exchange.to_s.upcase}_#{suffix}"
28
+ expect { trader.sell_client.validate_env }.to raise_error(ArgumentError, "Exiting because missing required ENV variable $#{key}.")
29
+ ENV[key] = "some value"
23
30
  end
31
+ expect { trader.sell_client.validate_env }.not_to raise_error
24
32
  end
25
33
  end
26
34
 
27
35
  describe "#fetch_prices" do
28
- it "gets the right price set" do
36
+ it "gets the right price set", :vcr do
29
37
  stamp_price = Bitstamp.ticker.ask.to_f
30
38
  mtgox_price = MtGox.ticker.buy
31
-
32
- @trader.fetch_prices
39
+
40
+ trader.fetch_prices
33
41
 
34
42
  #allow for recent price changes
35
- @trader.mtgox[:price].should be_within(0.02).of(mtgox_price)
36
- @trader.stamp[:price].should be_within(0.02).of(stamp_price)
43
+ trader.buyer[:price].should be_within(0.02).of(stamp_price)
44
+ trader.seller[:price].should be_within(0.02).of(mtgox_price)
45
+ end
46
+ end
47
+
48
+ describe "#initialize" do
49
+ let(:options) {
50
+ {
51
+ volume: 1,
52
+ cutoff: 1,
53
+ logger: nil,
54
+ verbose: false,
55
+ live: true,
56
+ seller: :bitstamp,
57
+ buyer: :mtgox,
58
+ }
59
+ }
60
+
61
+ let(:trader) { RbtcArbitrage::Trader.new(options) }
62
+
63
+ it "sets the right options" do
64
+ trader #memoize
65
+ options.each do |k,v|
66
+ next if [:seller,:buyer].include?(k)
67
+ trader.options[k].should == v
68
+ end
69
+ end
70
+
71
+ it "sets the right exchanges" do
72
+ trader.buy_client.should be_a(RbtcArbitrage::Clients::MtGoxClient)
73
+ trader.sell_client.should be_a(RbtcArbitrage::Clients::BitstampClient)
74
+ end
75
+
76
+ end
77
+
78
+ describe "#execute_trade" do
79
+ it "should raise SecurityError if not live", :vcr do
80
+ expect { trader.execute_trade }.to raise_error(SecurityError)
81
+ end
82
+
83
+ context "when live" do
84
+ let(:trader) { RbtcArbitrage::Trader.new(verbose: false, cutoff: 100, live: true) }
85
+
86
+ it "shouldn't raise security error", :vcr do
87
+ expect { trader.execute_trade }.not_to raise_error
88
+ end
89
+
90
+ it "should fetch balance", :vcr do
91
+ trader.should_receive(:get_balance)
92
+ trader.execute_trade
93
+ end
94
+
95
+ it "raises SecurityError if not enough USD", :vcr do
96
+ trader.instance_variable_set :@percent, 101
97
+ trader.instance_variable_set :@paid, 10000
98
+ trader.buyer[:usd] = 0
99
+ expect { trader.execute_trade }.to raise_error(SecurityError)
100
+ end
101
+
102
+ it "raises SecurityError if not enough BTC", :vcr do
103
+ trader.instance_variable_set :@percent, 101
104
+ trader.instance_variable_set :@paid, 1
105
+ trader.buyer[:usd] = 2
106
+ trader.options[:volume] = 1
107
+ trader.seller[:btc] = 0
108
+ expect { trader.execute_trade }.to raise_error(SecurityError)
109
+ end
110
+
111
+ it "should buy and sell" do
112
+ trader.instance_variable_set :@percent, 101
113
+ trader.instance_variable_set :@paid, 1
114
+ trader.buyer[:usd] = 2
115
+ trader.options[:volume] = 1
116
+ trader.seller[:btc] = 2
117
+ trader.should_receive :get_balance
118
+ trader.buy_client.should_receive(:buy)
119
+ trader.sell_client.should_receive(:sell)
120
+ trader.buy_client.should_receive(:transfer).with(trader.sell_client)
121
+ trader.execute_trade
122
+ end
123
+ end
124
+ end
125
+
126
+ describe "#trade" do
127
+ it "calls the right methods" do
128
+ trader.should_receive(:fetch_prices)
129
+ trader.should_not_receive(:log_info)
130
+ trader.should_not_receive(:execute_trade)
131
+
132
+ trader.instance_variable_set :@percent, 0
133
+
134
+ trader.trade
37
135
  end
136
+
137
+ it "raises SecurityError if cutoff > percent" do
138
+ trader.options[:live] = true
139
+ trader.options[:cutoff] = 10
140
+ trader.instance_variable_set :@percent, 1
141
+
142
+ trader.should_receive(:fetch_prices)
143
+ trader.should_not_receive(:log_info)
144
+
145
+ expect { trader.trade }.to raise_error(SecurityError)
146
+ end
147
+
148
+ it "calls #execute_trade if percent > cutoff" do
149
+ trader.options[:live] = true
150
+ trader.options[:cutoff] = 1
151
+ trader.instance_variable_set :@percent, 10
152
+
153
+ trader.should_receive(:fetch_prices)
154
+ trader.should_not_receive(:log_info)
155
+ trader.should_receive(:execute_trade)
156
+
157
+ trader.trade
158
+ end
159
+ end
160
+
161
+ describe "#log_info" do
162
+ it "calls logger.info" do
163
+ trader.buyer[:price] = 1
164
+ trader.seller[:price] = 1
165
+ trader.instance_variable_set :@percent, 1
166
+ trader.instance_variable_set :@paid, 1
167
+ trader.instance_variable_set :@received, 1
168
+ trader.logger.should_receive(:info).exactly(5).times
169
+ trader.log_info
170
+ end
171
+ end
172
+
173
+ describe "#logger" do
174
+ it { trader.logger.should == trader.options[:logger] }
38
175
  end
39
176
 
40
177
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbtc_arbitrage
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hank Stoever
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-07-09 00:00:00.000000000 Z
11
+ date: 2013-12-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -28,84 +28,112 @@ dependencies:
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ! '>='
31
+ - - '>='
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ! '>='
38
+ - - '>='
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: mtgox
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ! '>='
45
+ - - '>='
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ! '>='
52
+ - - '>='
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: bitstamp
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ! '>='
59
+ - - '>='
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ! '>='
66
+ - - '>='
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: activemodel
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ! '>='
73
+ - - '>='
74
74
  - !ruby/object:Gem::Version
75
75
  version: '3.1'
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ! '>='
80
+ - - '>='
81
81
  - !ruby/object:Gem::Version
82
82
  version: '3.1'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: activesupport
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ! '>='
87
+ - - '>='
88
88
  - !ruby/object:Gem::Version
89
89
  version: '3.1'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ! '>='
94
+ - - '>='
95
95
  - !ruby/object:Gem::Version
96
96
  version: '3.1'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: thor
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ! '>='
101
+ - - '>='
102
102
  - !ruby/object:Gem::Version
103
103
  version: '0'
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - ! '>='
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: btce
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: bitstamp
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '>='
109
137
  - !ruby/object:Gem::Version
110
138
  version: '0'
111
139
  description: A gem for conducting arbitrage with Bitcoin.
@@ -120,16 +148,41 @@ files:
120
148
  - .rspec
121
149
  - .travis.yml
122
150
  - Gemfile
151
+ - Guardfile
123
152
  - LICENSE.txt
124
153
  - README.md
125
154
  - Rakefile
126
155
  - bin/rbtc
156
+ - btce-api-key.yml
127
157
  - lib/rbtc_arbitrage.rb
158
+ - lib/rbtc_arbitrage/campbx.rb
128
159
  - lib/rbtc_arbitrage/cli.rb
160
+ - lib/rbtc_arbitrage/client.rb
161
+ - lib/rbtc_arbitrage/clients/bitstamp_client.rb
162
+ - lib/rbtc_arbitrage/clients/mtgox_client.rb
129
163
  - lib/rbtc_arbitrage/trader.rb
130
164
  - lib/rbtc_arbitrage/version.rb
131
165
  - rbtc_arbitrage.gemspec
166
+ - spec/cli_spec.rb
167
+ - spec/client_spec.rb
168
+ - spec/clients/bitstamp_client_spec.rb
169
+ - spec/clients/mtgox_client_spec.rb
132
170
  - spec/spec_helper.rb
171
+ - spec/support/cassettes/RbtcArbitrage_Clients_BitstampClient/_balance/fetches_the_balance_correctly.yml
172
+ - spec/support/cassettes/RbtcArbitrage_Clients_BitstampClient/_price/fetches_price_for_buy_correctly.yml
173
+ - spec/support/cassettes/RbtcArbitrage_Clients_BitstampClient/_price/fetches_price_for_sell_correctly.yml
174
+ - spec/support/cassettes/RbtcArbitrage_Clients_BitstampClient/_price/fetches_prices_correctly.yml
175
+ - spec/support/cassettes/RbtcArbitrage_Clients_MtGoxClient/_balance/fetches_the_balance_correctly.yml
176
+ - spec/support/cassettes/RbtcArbitrage_Clients_MtGoxClient/_price/fetches_price_for_buy_correctly.yml
177
+ - spec/support/cassettes/RbtcArbitrage_Clients_MtGoxClient/_price/fetches_price_for_sell_correctly.yml
178
+ - spec/support/cassettes/RbtcArbitrage_Clients_MtGoxClient/_price/fetches_prices_correctly.yml
179
+ - spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/should_raise_SecurityError_if_not_live.yml
180
+ - spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/when_live/raises_SecurityError_if_not_enough_BTC.yml
181
+ - spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/when_live/raises_SecurityError_if_not_enough_USD.yml
182
+ - spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/when_live/should_fetch_balance.yml
183
+ - spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/when_live/shouldn_t_raise_security_error.yml
184
+ - spec/support/cassettes/RbtcArbitrage_Trader/_fetch_prices/gets_the_right_price_set.yml
185
+ - spec/support/cassettes/RbtcArbitrage_Trader/_get_balance/fetches_the_right_balance.yml
133
186
  - spec/trader_spec.rb
134
187
  homepage: ''
135
188
  licenses:
@@ -141,21 +194,39 @@ require_paths:
141
194
  - lib
142
195
  required_ruby_version: !ruby/object:Gem::Requirement
143
196
  requirements:
144
- - - ! '>='
197
+ - - '>='
145
198
  - !ruby/object:Gem::Version
146
199
  version: '0'
147
200
  required_rubygems_version: !ruby/object:Gem::Requirement
148
201
  requirements:
149
- - - ! '>='
202
+ - - '>='
150
203
  - !ruby/object:Gem::Version
151
204
  version: '0'
152
205
  requirements: []
153
206
  rubyforge_project:
154
- rubygems_version: 2.0.3
207
+ rubygems_version: 2.0.6
155
208
  signing_key:
156
209
  specification_version: 4
157
210
  summary: A gem for conducting arbitrage with Bitcoin.
158
211
  test_files:
212
+ - spec/cli_spec.rb
213
+ - spec/client_spec.rb
214
+ - spec/clients/bitstamp_client_spec.rb
215
+ - spec/clients/mtgox_client_spec.rb
159
216
  - spec/spec_helper.rb
217
+ - spec/support/cassettes/RbtcArbitrage_Clients_BitstampClient/_balance/fetches_the_balance_correctly.yml
218
+ - spec/support/cassettes/RbtcArbitrage_Clients_BitstampClient/_price/fetches_price_for_buy_correctly.yml
219
+ - spec/support/cassettes/RbtcArbitrage_Clients_BitstampClient/_price/fetches_price_for_sell_correctly.yml
220
+ - spec/support/cassettes/RbtcArbitrage_Clients_BitstampClient/_price/fetches_prices_correctly.yml
221
+ - spec/support/cassettes/RbtcArbitrage_Clients_MtGoxClient/_balance/fetches_the_balance_correctly.yml
222
+ - spec/support/cassettes/RbtcArbitrage_Clients_MtGoxClient/_price/fetches_price_for_buy_correctly.yml
223
+ - spec/support/cassettes/RbtcArbitrage_Clients_MtGoxClient/_price/fetches_price_for_sell_correctly.yml
224
+ - spec/support/cassettes/RbtcArbitrage_Clients_MtGoxClient/_price/fetches_prices_correctly.yml
225
+ - spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/should_raise_SecurityError_if_not_live.yml
226
+ - spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/when_live/raises_SecurityError_if_not_enough_BTC.yml
227
+ - spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/when_live/raises_SecurityError_if_not_enough_USD.yml
228
+ - spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/when_live/should_fetch_balance.yml
229
+ - spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/when_live/shouldn_t_raise_security_error.yml
230
+ - spec/support/cassettes/RbtcArbitrage_Trader/_fetch_prices/gets_the_right_price_set.yml
231
+ - spec/support/cassettes/RbtcArbitrage_Trader/_get_balance/fetches_the_right_balance.yml
160
232
  - spec/trader_spec.rb
161
- has_rdoc: