rbtc_arbitrage_simple 1.2.3
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 +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
|
+
[](https://travis-ci.org/hstove/rbtc_arbitrage)
|
|
16
|
+
[](https://coveralls.io/r/hstove/rbtc_arbitrage)
|
|
17
|
+
[](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
|