rbtc_arbitrage_simple 1.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.rspec +2 -0
- data/.travis.yml +23 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +156 -0
- data/Guardfile +8 -0
- data/LICENSE.txt +22 -0
- data/Procfile +1 -0
- data/README.md +88 -0
- data/Rakefile +10 -0
- data/bin/rbtc_simple +4 -0
- data/dummy_web_server.rb +9 -0
- data/lib/rbtc_arbitrage.rb +15 -0
- data/lib/rbtc_arbitrage/campbx.rb +98 -0
- data/lib/rbtc_arbitrage/cli.rb +19 -0
- data/lib/rbtc_arbitrage/client.rb +48 -0
- data/lib/rbtc_arbitrage/clients/btce_client.rb +62 -0
- data/lib/rbtc_arbitrage/clients/campbx_client.rb +48 -0
- data/lib/rbtc_arbitrage/clients/client.rb.example +46 -0
- data/lib/rbtc_arbitrage/clients/coinbase_client.rb +63 -0
- data/lib/rbtc_arbitrage/clients/mtgox_client.rb +56 -0
- data/lib/rbtc_arbitrage/trader.rb +123 -0
- data/lib/rbtc_arbitrage/version.rb +3 -0
- data/rbtc_arbitrage.gemspec +30 -0
- data/spec/cli_spec.rb +8 -0
- data/spec/client_spec.rb +33 -0
- data/spec/clients/btce_client_spec.rb +93 -0
- data/spec/clients/campbx_client_spec.rb +66 -0
- data/spec/clients/coinbase_client_spec.rb +66 -0
- data/spec/clients/mtgox_client_spec.rb +53 -0
- data/spec/rbtc_arbitrage_spec.rb +11 -0
- data/spec/spec_helper.rb +34 -0
- data/spec/support/cassettes/RbtcArbitrage_Clients_BitstampClient/_balance/fetches_the_balance_correctly.yml +96 -0
- data/spec/support/cassettes/RbtcArbitrage_Clients_BitstampClient/_price/fetches_price_for_buy_correctly.yml +52 -0
- data/spec/support/cassettes/RbtcArbitrage_Clients_BitstampClient/_price/fetches_price_for_sell_correctly.yml +52 -0
- data/spec/support/cassettes/RbtcArbitrage_Clients_BitstampClient/_price/fetches_prices_correctly.yml +44 -0
- data/spec/support/cassettes/RbtcArbitrage_Clients_BtceClient/_balance/should_raise_if_bad_API_keys.yml +53 -0
- data/spec/support/cassettes/RbtcArbitrage_Clients_BtceClient/_price/calls_btc-e.yml +91 -0
- data/spec/support/cassettes/RbtcArbitrage_Clients_BtceClient/_price/fetches_price_for_buy_correctly.yml +47 -0
- data/spec/support/cassettes/RbtcArbitrage_Clients_BtceClient/_price/fetches_price_for_sell_correctly.yml +47 -0
- data/spec/support/cassettes/RbtcArbitrage_Clients_CampbxClient/_balance/fetches_the_balance_correctly.yml +95 -0
- data/spec/support/cassettes/RbtcArbitrage_Clients_CampbxClient/_price/fetches_price_for_buy_correctly.yml +49 -0
- data/spec/support/cassettes/RbtcArbitrage_Clients_CampbxClient/_price/fetches_price_for_sell_correctly.yml +49 -0
- data/spec/support/cassettes/RbtcArbitrage_Clients_CoinbaseClient/_balance/fetches_the_balance_correctly.yml +109 -0
- data/spec/support/cassettes/RbtcArbitrage_Clients_CoinbaseClient/_price/calls_coinbase.yml +215 -0
- data/spec/support/cassettes/RbtcArbitrage_Clients_CoinbaseClient/_price/fetches_price_for_buy_correctly.yml +56 -0
- data/spec/support/cassettes/RbtcArbitrage_Clients_CoinbaseClient/_price/fetches_price_for_sell_correctly.yml +56 -0
- data/spec/support/cassettes/RbtcArbitrage_Clients_MtGoxClient/_balance/fetches_the_balance_correctly.yml +77 -0
- data/spec/support/cassettes/RbtcArbitrage_Clients_MtGoxClient/_price/fetches_price_for_buy_correctly.yml +44 -0
- data/spec/support/cassettes/RbtcArbitrage_Clients_MtGoxClient/_price/fetches_price_for_sell_correctly.yml +44 -0
- data/spec/support/cassettes/RbtcArbitrage_Clients_MtGoxClient/_price/fetches_prices_correctly.yml +85 -0
- data/spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/should_raise_SecurityError_if_not_live.yml +88 -0
- data/spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/when_live/raises_SecurityError_if_not_enough_BTC.yml +81 -0
- data/spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/when_live/raises_SecurityError_if_not_enough_USD.yml +81 -0
- data/spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/when_live/should_fetch_balance.yml +88 -0
- data/spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/when_live/shouldn_t_raise_security_error.yml +166 -0
- data/spec/support/cassettes/RbtcArbitrage_Trader/_fetch_prices/gets_the_right_price_set.yml +173 -0
- data/spec/trader_spec.rb +228 -0
- metadata +249 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 40fce7b383de7c133941d19f55ff55adaf3fa01d
|
4
|
+
data.tar.gz: d625c40f8afee77529f458183cf32fba33fef0d8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8c08ee2166aafcd8dbd14dfa1a02ae5e0c14881b1b778b906fa6662e13ccc04770d2e7aae4e66c9da16a01b6a42188719030d758ea1f59282cd2b6392910f7ee
|
7
|
+
data.tar.gz: a8ef905fc4e189aa20ff6839440960f1e00c744119142d8e0b69af44af1eb226b98c80fc7bd6b7766ab7d79696d04b78a88049efbd732e245faf02f5d97096e9
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.1.0
|
4
|
+
- 2.0.0
|
5
|
+
- 1.9.3
|
6
|
+
- ruby-head
|
7
|
+
- jruby-19mode
|
8
|
+
- jruby-head
|
9
|
+
env:
|
10
|
+
global:
|
11
|
+
- secure: FdoR9cSL5JzSiGRgmrEGCx55VdP7QU6jt2vzeJyc+2Ho67UXxJuXWgFdwojs6X85O3in8YfSOInBLGXXsD8a3mBuvhsAaMmDLbhFKfEExsc9bnpTj3k95UMGRO3pGNkk1tfj/ohsLFs+yL4r/mFZ5pOoxWW0uhYuRPA+Jk39hZg=
|
12
|
+
- secure: k8OmNupst65nssbCEYLnUdJdYvwnW6YUqcBCNOLcxXKRWcABf2RGmfI/T/iyO0uzzF6e9Ms3C9eZixfIXw4BVTY7DajKHicjvUMPMzzAwAqpK9fb2+mHUmNuksl8wjLvZB4j3TkAAxMECjpPQ2TvY1NRj375STUICC1Ahk9V6CU=
|
13
|
+
- secure: DTjDDBK+lKN6unPF1WOj8a/IIEcty4hkqeP2brilboAyKczxxuDkWcEY7q4mr1whzSQqnWgZgKH2my7mJwWm+J8DMW4bkD5se6eQtmHB/lXkIkIUxHdHT1KM5o+8MqMnb8PX7gquudeIGwNfI2yXa8Nh33y/fVCiKsMDg25Z8Es=
|
14
|
+
- secure: VDB+4rlwVZHOVDQanlAp/QD6owxd5RtiOCUC1H/NudyFqAeXUrn57FC8IN4f4s5Mk7mW9M7F7VYF2l4egjfVYszjq3OlUaWb5uMS7LSVl7I4rNaCM+pPA4vi7rlt6F0LqZoDJzNX7Md1SwIQjCBracRbpV3ZKL8GHh5yS3Ojk38=
|
15
|
+
- secure: ksmMGyDkwmIUkJIHzdrAld+GN2KEm9l8dtxZikoP7B9zRymhnPhImDfZHbByFV0DIZmNiUMFvNLIIpgznjpFdpcEjCbLQnfniKTscMyQZ1pvOesCyaPnSHBENRDsADFCG/TMeP5VXtUUL2k/eNIzHU0cVJT8JaEMdihPDy+mrO8=
|
16
|
+
- secure: I3rS8d84BoCsZo9c/PcY6F/GDThVu/rPKMjTUGHkbtWXVD8E809JxaWavu/+EesyUhn8dDGwMRUc+4d6gtk+QeQVOyLkkPIaCII4puJEHqdyJpqrJlsZbXaGO/JJ6mx2y0I6wDryKeLhZqVn6VdxycF+7OTqYdCFGV+o49wirIU=
|
17
|
+
- secure: kih2LqMwQDZErJFU4hslPZcAdtYwQIYyzxnkObIWtIQpLAVQNssbISLBe5ogWNXi8FyiEktAH5Yy0orjTp2ynmrA6rE6NU/vD3oBDeeI7CCd+13weeIW+uReyixuI5zn6zzJLHdxn+rUwowfdYrt9vF54uEjKCVL32pbLZjdavk=
|
18
|
+
- secure: Y4BCviYqCE0JnumhmuIdGp79qQUMiTjBPruQszf65vivmD3jKXXldY0AzUpxUpHwHVAI755Xyc80IuIFQfo+w2gykK18DFKVuKjRqxxqzRKMzf6sB+haXOm0vK0+2y2E1q9EX7DygXuxuDtGRAOKsvPRZWgPERH67bR+e2mR4+0=
|
19
|
+
- secure: bKrqQ2Q2Rp7aR8yGYLplTCPLXck3BbpJsCirxoX6mJpDUsZTiM+sCxHKDnTeBptNaFfJe1JKb0xKhzu9CuY2gHi+XtrUu/yAq4M0+3vWG8h7Ios4ztI2BTnM4yi6vYaKkhdRrHFPdNdiL1/+bWW9/4SH1yOfw17UpnT3YbBdX4s=
|
20
|
+
- secure: YLXu/SNHJrhqc6Go9Tk7A2Dwf8XncZtGfRKwSbMb6WdNNw/8Zfd49tcf6FbiJS/THah5j/x4+X6kcxbCzgxndfIqpJNSn5gndYLWHIMWZ4B+ppM76SyvqsyrCWWWBcbnuKI8/FhN+1jvdKCRC1XO5hFbdBLqXMXjrcqTFF78k/Y=
|
21
|
+
- secure: IFyJX6lAmBpef0I50UPCy6L5IRxqRKoPhv74s5y0FPB4chrir7iMZ7Sd1IczxV7ly4Dt7hdALHP1qMTmkcGmTV6YOzwR46G4JAwWtX2xlf4OYk4jey7qjNsS6iijD6dvdYjqSKUuGaX3Til3kUOLcA3hhINvHxj5unv2pHB2W70=
|
22
|
+
- secure: YiYtCBJNfgWuzQ059RMmZxM00bs4c/GuqaEaKufLPPByJHHt3z4jCNT5lurox/RIqSYTv+1Nvgor1xJZF4VPDIhtoCpVRe3g5Pvubrp4gWQry11ta0f1JhPSrm5ORlF1hpHPfzHHSh+/YVmKcO8agQAaIgfKcXDzsE6j5QqiGWQ=
|
23
|
+
- secure: TCrSkWTG2A7ZHxU/J82R1oRn3+ISYHOZmukvBT/OkOh35yjhtig3KhroYki67guCClVxov+ZPvCRUKgmsEoVng1ljk/ZXyyNf4QNVccEJxHCwIRiqs36jlC2ebd8g+JJUPrnnWGO/U5vBm+WlrOb4lFlIsBuCYI+FBAFYTPmKEs=
|
data/Gemfile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in rbtc_arbitrage.gemspec
|
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'
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
rbtc_arbitrage_simple (1.2.3)
|
5
|
+
activemodel (>= 3.1)
|
6
|
+
activesupport (>= 3.1)
|
7
|
+
btce (= 0.2.4)
|
8
|
+
coinbase (= 1.2.4)
|
9
|
+
mtgox
|
10
|
+
thor
|
11
|
+
|
12
|
+
GEM
|
13
|
+
remote: https://rubygems.org/
|
14
|
+
specs:
|
15
|
+
activemodel (4.0.2)
|
16
|
+
activesupport (= 4.0.2)
|
17
|
+
builder (~> 3.1.0)
|
18
|
+
activesupport (4.0.2)
|
19
|
+
i18n (~> 0.6, >= 0.6.4)
|
20
|
+
minitest (~> 4.2)
|
21
|
+
multi_json (~> 1.3)
|
22
|
+
thread_safe (~> 0.1)
|
23
|
+
tzinfo (~> 0.3.37)
|
24
|
+
addressable (2.3.5)
|
25
|
+
atomic (1.1.14)
|
26
|
+
btce (0.2.4)
|
27
|
+
monkey-patch
|
28
|
+
builder (3.1.4)
|
29
|
+
celluloid (0.15.2)
|
30
|
+
timers (~> 1.1.0)
|
31
|
+
codeclimate-test-reporter (0.2.0)
|
32
|
+
simplecov (>= 0.7.1, < 1.0.0)
|
33
|
+
coderay (1.1.0)
|
34
|
+
coinbase (1.2.4)
|
35
|
+
hashie (>= 1.2.0)
|
36
|
+
httparty (>= 0.8.3)
|
37
|
+
money (>= 4.0.1)
|
38
|
+
multi_json (>= 1.3.4)
|
39
|
+
coveralls (0.7.0)
|
40
|
+
multi_json (~> 1.3)
|
41
|
+
rest-client
|
42
|
+
simplecov (>= 0.7)
|
43
|
+
term-ansicolor
|
44
|
+
thor
|
45
|
+
crack (0.4.1)
|
46
|
+
safe_yaml (~> 0.9.0)
|
47
|
+
diff-lcs (1.2.5)
|
48
|
+
docile (1.1.1)
|
49
|
+
faraday (0.8.8)
|
50
|
+
multipart-post (~> 1.2.0)
|
51
|
+
ffi (1.9.3)
|
52
|
+
formatador (0.2.4)
|
53
|
+
guard (2.2.5)
|
54
|
+
formatador (>= 0.2.4)
|
55
|
+
listen (~> 2.1)
|
56
|
+
lumberjack (~> 1.0)
|
57
|
+
pry (>= 0.9.12)
|
58
|
+
thor (>= 0.18.1)
|
59
|
+
guard-rspec (4.2.1)
|
60
|
+
guard (>= 2.1.1)
|
61
|
+
rspec (~> 3.0.0.beta, >= 2.14, < 4.0)
|
62
|
+
hashie (2.0.5)
|
63
|
+
httparty (0.12.0)
|
64
|
+
json (~> 1.8)
|
65
|
+
multi_xml (>= 0.5.2)
|
66
|
+
i18n (0.6.9)
|
67
|
+
json (1.8.1)
|
68
|
+
listen (2.4.0)
|
69
|
+
celluloid (>= 0.15.2)
|
70
|
+
rb-fsevent (>= 0.9.3)
|
71
|
+
rb-inotify (>= 0.9)
|
72
|
+
lumberjack (1.0.4)
|
73
|
+
method_source (0.8.2)
|
74
|
+
mime-types (2.0)
|
75
|
+
minitest (4.7.5)
|
76
|
+
money (6.0.0)
|
77
|
+
i18n (~> 0.6.4)
|
78
|
+
monkey-patch (0.0.14)
|
79
|
+
activesupport
|
80
|
+
mtgox (1.1.0)
|
81
|
+
faraday (~> 0.8, < 0.10)
|
82
|
+
json (~> 1.7, >= 1.7.7)
|
83
|
+
multi_json (1.8.2)
|
84
|
+
multi_xml (0.5.5)
|
85
|
+
multipart-post (1.2.0)
|
86
|
+
pry (0.9.12.4)
|
87
|
+
coderay (~> 1.0)
|
88
|
+
method_source (~> 0.8)
|
89
|
+
slop (~> 3.4)
|
90
|
+
rack (1.5.2)
|
91
|
+
rack-protection (1.5.1)
|
92
|
+
rack
|
93
|
+
rake (10.1.1)
|
94
|
+
rb-fsevent (0.9.3)
|
95
|
+
rb-inotify (0.9.3)
|
96
|
+
ffi (>= 0.5.0)
|
97
|
+
rest-client (1.6.7)
|
98
|
+
mime-types (>= 1.16)
|
99
|
+
rspec (3.0.0.beta1)
|
100
|
+
rspec-core (= 3.0.0.beta1)
|
101
|
+
rspec-expectations (= 3.0.0.beta1)
|
102
|
+
rspec-mocks (= 3.0.0.beta1)
|
103
|
+
rspec-core (3.0.0.beta1)
|
104
|
+
rspec-support (= 3.0.0.beta1)
|
105
|
+
rspec-expectations (3.0.0.beta1)
|
106
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
107
|
+
rspec-support (= 3.0.0.beta1)
|
108
|
+
rspec-mocks (3.0.0.beta1)
|
109
|
+
rspec-support (= 3.0.0.beta1)
|
110
|
+
rspec-support (3.0.0.beta1)
|
111
|
+
ruby_gntp (0.3.4)
|
112
|
+
safe_yaml (0.9.7)
|
113
|
+
simplecov (0.8.2)
|
114
|
+
docile (~> 1.1.0)
|
115
|
+
multi_json
|
116
|
+
simplecov-html (~> 0.8.0)
|
117
|
+
simplecov-html (0.8.0)
|
118
|
+
sinatra (1.4.4)
|
119
|
+
rack (~> 1.4)
|
120
|
+
rack-protection (~> 1.4)
|
121
|
+
tilt (~> 1.3, >= 1.3.4)
|
122
|
+
slop (3.4.7)
|
123
|
+
term-ansicolor (1.2.2)
|
124
|
+
tins (~> 0.8)
|
125
|
+
thor (0.18.1)
|
126
|
+
thread_safe (0.1.3)
|
127
|
+
atomic
|
128
|
+
tilt (1.4.1)
|
129
|
+
timers (1.1.0)
|
130
|
+
tins (0.13.1)
|
131
|
+
tzinfo (0.3.38)
|
132
|
+
vcr (2.8.0)
|
133
|
+
webmock (1.16.1)
|
134
|
+
addressable (>= 2.2.7)
|
135
|
+
crack (>= 0.3.2)
|
136
|
+
|
137
|
+
PLATFORMS
|
138
|
+
ruby
|
139
|
+
|
140
|
+
DEPENDENCIES
|
141
|
+
activemodel (>= 3.1)
|
142
|
+
activesupport (>= 3.1)
|
143
|
+
bundler (~> 1.3)
|
144
|
+
codeclimate-test-reporter
|
145
|
+
coveralls
|
146
|
+
guard
|
147
|
+
guard-rspec
|
148
|
+
hashie
|
149
|
+
rake
|
150
|
+
rbtc_arbitrage_simple!
|
151
|
+
rspec
|
152
|
+
ruby_gntp
|
153
|
+
simplecov
|
154
|
+
sinatra
|
155
|
+
vcr
|
156
|
+
webmock
|
data/Guardfile
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
guard 'rspec' do
|
2
|
+
watch(%r{^spec/.+_spec\.rb$})
|
3
|
+
watch(%r{^lib/rbtc_arbitrage/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
4
|
+
watch('spec/spec_helper.rb') { 'spec' }
|
5
|
+
watch(%r{^spec/clients/.+_spec\.rb$})
|
6
|
+
watch(%r{^lib/rbtc_arbitrage/clients/(.+)\.rb$}) { |m| "spec/clients/#{m[1]}_spec.rb" }
|
7
|
+
end
|
8
|
+
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Hank Stoever
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Procfile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
web: bundle exec ruby dummy_web_server.rb -p $PORT
|
data/README.md
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
# RbtcArbitrage
|
2
|
+
|
3
|
+
A Ruby gem for executing arbitrage between the MtGox and Bitstamp bitcoin exchanges.
|
4
|
+
|
5
|
+
## Meta
|
6
|
+
|
7
|
+
[Explanation of bitcoin arbitrage](http://hankstoever.com/posts/13-Everything-you-need-to-know-about-Bitcoin-arbitrage)
|
8
|
+
|
9
|
+
[Why I open sourced a bitcoin arbitrate bot](http://hankstoever.com/posts/2-Why-I-open-sourced-a-bitcoin-arbitrage-bot)
|
10
|
+
|
11
|
+
I'm also creating a course on [creating your own bitcoin arbitrage bot](https://www.uludum.org/funds/2)
|
12
|
+
|
13
|
+
Donations accepted: **16BMcqf93eEpb2aWgMkJCSQQH85WzrpbdZ**
|
14
|
+
|
15
|
+
[![Build Status](https://travis-ci.org/hstove/rbtc_arbitrage.png?branch=master)](https://travis-ci.org/hstove/rbtc_arbitrage)
|
16
|
+
[![Coverage Status](https://coveralls.io/repos/hstove/rbtc_arbitrage/badge.png)](https://coveralls.io/r/hstove/rbtc_arbitrage)
|
17
|
+
[![Code Climate](https://codeclimate.com/github/hstove/rbtc_arbitrage.png)](https://codeclimate.com/github/hstove/rbtc_arbitrage)
|
18
|
+
|
19
|
+
## Installation
|
20
|
+
|
21
|
+
Install it yourself as:
|
22
|
+
|
23
|
+
$ gem install rbtc_arbitrage
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
After installing the gem, simply run `rbtc` in the command line.
|
28
|
+
|
29
|
+
#### Options
|
30
|
+
|
31
|
+
- **Live**: whether you want to actually execute trades. You must have configured your API keys and bitcoin addresses through the following environment variables:
|
32
|
+
1. MTGOX_KEY
|
33
|
+
2. MTGOX_SECRET
|
34
|
+
2. MTGOX_ADDRESS
|
35
|
+
2. BITSTAMP_KEY
|
36
|
+
2. BITSTAMP_SECRET
|
37
|
+
3. BITSTAMP_ADDRESS
|
38
|
+
4. BITSTAMP_CLIENT_ID
|
39
|
+
|
40
|
+
- **Cutoff**: the minimum profit percentage required to execute a trade. Defaults to **%2.00**.
|
41
|
+
- **Volume**: The amount of bitcoins to trade per transaction. Defaults to **0.01** (the minimum transaction size).
|
42
|
+
- **Buyer**: The exchange you'd like to buy bitcoins from during arbitrage. `"mtgox"` or `"bitstamp"`. Default is `bitstamp`
|
43
|
+
- **Seller**: The exchange you'd like to sell bitcoins from during arbitrage. `"mtgox"` or `"bitstamp"`. Default is `mtgox`
|
44
|
+
|
45
|
+
#### Examples
|
46
|
+
|
47
|
+
$ rbtc --live --cutoff 4
|
48
|
+
$ rbtc --cutoff 0.5
|
49
|
+
$ rbtc --cutoff 3 --volume 0.05
|
50
|
+
$ rbtc --seller bitstamp --buyer mtgox
|
51
|
+
$ rbtc
|
52
|
+
|
53
|
+
The output will look like this:
|
54
|
+
|
55
|
+
07/08/2013 at 10:41AM
|
56
|
+
Retrieving market information and balances
|
57
|
+
Bitstamp: $74.0
|
58
|
+
MtGox: $76.89
|
59
|
+
buying 0.01 btc from Bitstamp for $0.74
|
60
|
+
selling 0.01 btc on MtGox for $0.76
|
61
|
+
profit: $0.02 (2.77%)
|
62
|
+
|
63
|
+
## Changelog
|
64
|
+
|
65
|
+
See [releases](https://github.com/hstove/rbtc_arbitrage/releases).
|
66
|
+
|
67
|
+
## Contributing
|
68
|
+
|
69
|
+
### Pull Requests are welcome!
|
70
|
+
|
71
|
+
1. Fork it
|
72
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
73
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
74
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
75
|
+
5. Create new Pull Request
|
76
|
+
|
77
|
+
## Adding an exchange
|
78
|
+
|
79
|
+
Right now there is support for only MtGox and Bitstamp, but adding support for other exchanges is dead simple. First, you'll need to create a new `client` in `lib/rbtc_arbitrage/clients`. Follow the example from the [mtgox client](https://github.com/hstove/rbtc_arbitrage/blob/master/lib/rbtc_arbitrage/clients/mtgox_client.rb). You'll need to provide custom implementations of the following methods:
|
80
|
+
|
81
|
+
- `validate_env`
|
82
|
+
- `balance`
|
83
|
+
- `price`
|
84
|
+
- `trade`
|
85
|
+
- `exchange`
|
86
|
+
- `transfer`
|
87
|
+
|
88
|
+
Make sure that the methods accept the same arguments and return similar objects. At the same time, make sure you copy the [mtgox_cient_spec](https://github.com/hstove/rbtc_arbitrage/blob/master/spec/clients/mtgox_client_spec.rb) and change it to test your client.
|
data/Rakefile
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
|
4
|
+
desc "Run specs"
|
5
|
+
RSpec::Core::RakeTask.new do |t|
|
6
|
+
# t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
|
7
|
+
# Put spec opts in a file named .rspec in root
|
8
|
+
end
|
9
|
+
|
10
|
+
task default: :spec
|
data/bin/rbtc_simple
ADDED
data/dummy_web_server.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'mtgox'
|
3
|
+
require_relative 'rbtc_arbitrage/campbx.rb'
|
4
|
+
require 'btce'
|
5
|
+
require 'coinbase'
|
6
|
+
require_relative 'rbtc_arbitrage/client.rb'
|
7
|
+
Dir["#{File.dirname(__FILE__)}/rbtc_arbitrage/**/*.rb"].each { |f| require(f) }
|
8
|
+
|
9
|
+
module RbtcArbitrage
|
10
|
+
def self.clients
|
11
|
+
RbtcArbitrage::Clients.constants.collect do |c|
|
12
|
+
RbtcArbitrage::Clients.const_get(c)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
## Ruby module for working with CampBX API
|
2
|
+
## May 2013
|
3
|
+
## based on glenbot's python work @ https://github.com/glenbot/campbx/
|
4
|
+
|
5
|
+
require 'json'
|
6
|
+
require 'net/http'
|
7
|
+
require 'uri'
|
8
|
+
|
9
|
+
module CampBX
|
10
|
+
API_BASE = 'https://campbx.com/api/'
|
11
|
+
|
12
|
+
# { method_name => [ url, auth?, [ parameters ] ] }
|
13
|
+
# See: https://campbx.com/api.php for specifics.
|
14
|
+
# Each method returns a Hash with JSON data from the API.
|
15
|
+
# Some parameters are optional.
|
16
|
+
CALLS = {
|
17
|
+
'xdepth' => [ 'xdepth', FALSE, [] ],
|
18
|
+
'xticker' => [ 'xticker', FALSE, [] ],
|
19
|
+
'my_funds' => ['myfunds', TRUE, [] ],
|
20
|
+
'my_orders' => ['myorders', TRUE, [] ],
|
21
|
+
'my_margins' => ['mymargins', TRUE, [] ],
|
22
|
+
'send_instant' => ['sendinstant', TRUE, [ 'CBXCode', 'BTCAmt' ] ],
|
23
|
+
'get_btc_address' => ['getbtcaddr', TRUE, [] ],
|
24
|
+
'send_btc' => ['sendbtc', TRUE, [ 'BTCTo', 'BTCAmt' ] ],
|
25
|
+
# 'dwolla' => [ nil, TRUE, [] ], # Coming Soon (TM)
|
26
|
+
'trade_cancel' => ['tradecancel', TRUE, [ 'Type', 'OrderID' ] ],
|
27
|
+
'trade_enter' => ['tradeenter', TRUE, [ 'TradeMode', 'Quantity', 'Price' ] ],
|
28
|
+
'trade_advanced' => ['tradeadv', TRUE, [ 'TradeMode', 'Price', 'Quantity', 'FillType', 'DarkPool', 'Expiry' ] ],
|
29
|
+
# 'margin_buy' => [ nil, TRUE, [] ], # Coming Soon (TM)
|
30
|
+
# 'short_sell' => [ nil, TRUE, [] ], # Coming Soon (TM)
|
31
|
+
}
|
32
|
+
|
33
|
+
|
34
|
+
class API
|
35
|
+
# CampBX API rate limiting probably per IP address (not account)
|
36
|
+
# which is why we don't limit per instance
|
37
|
+
@@last = Time.new(0)
|
38
|
+
@username = nil
|
39
|
+
@password = nil
|
40
|
+
|
41
|
+
def initialize( username=nil, password=nil )
|
42
|
+
@username = username
|
43
|
+
@password = password
|
44
|
+
|
45
|
+
# Build meta-methods for each API call
|
46
|
+
CALLS.each do |name|
|
47
|
+
define_singleton_method name[0], lambda { |*args|
|
48
|
+
data = CALLS[name[0]]
|
49
|
+
api_request( [data[0], data[1]], Hash[data[2].zip( args )] )
|
50
|
+
}
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def api_request( info, post_data={} )
|
55
|
+
url, auth = info
|
56
|
+
uri = URI.parse(API_BASE + url + '.php')
|
57
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
58
|
+
http.use_ssl=TRUE
|
59
|
+
# CampBX advises latency can be >4 minutes when markets are volatile
|
60
|
+
http.read_timeout = 300
|
61
|
+
res = nil
|
62
|
+
|
63
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
64
|
+
if auth then
|
65
|
+
post_data.merge!({
|
66
|
+
'user' => @username,
|
67
|
+
'pass' => @password,
|
68
|
+
})
|
69
|
+
request = Net::HTTP::Post.new(uri.request_uri)
|
70
|
+
request.set_form_data( post_data )
|
71
|
+
end
|
72
|
+
|
73
|
+
# debug # need to test w/valid credentials
|
74
|
+
#puts "Sending request to #{uri}"
|
75
|
+
#puts "Post Data: #{post_data}"
|
76
|
+
|
77
|
+
# CampBX API: max 1 request per 500ms
|
78
|
+
delta = Time.now - @@last
|
79
|
+
#puts delta*1000
|
80
|
+
if delta*1000 <= 500 then
|
81
|
+
#puts "sleeping! for #{0.5 - delta}"
|
82
|
+
sleep(0.5 - delta)
|
83
|
+
end
|
84
|
+
|
85
|
+
res = http.request(request)
|
86
|
+
@@last = Time.now # Update time after request returns
|
87
|
+
|
88
|
+
if res.message == 'OK' then # HTTP OK
|
89
|
+
JSON.parse( res.body )
|
90
|
+
else # HTTP ERROR
|
91
|
+
warn "HTTP Error: + #{res.code}"
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|