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.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +23 -0
  5. data/Gemfile +18 -0
  6. data/Gemfile.lock +156 -0
  7. data/Guardfile +8 -0
  8. data/LICENSE.txt +22 -0
  9. data/Procfile +1 -0
  10. data/README.md +88 -0
  11. data/Rakefile +10 -0
  12. data/bin/rbtc_simple +4 -0
  13. data/dummy_web_server.rb +9 -0
  14. data/lib/rbtc_arbitrage.rb +15 -0
  15. data/lib/rbtc_arbitrage/campbx.rb +98 -0
  16. data/lib/rbtc_arbitrage/cli.rb +19 -0
  17. data/lib/rbtc_arbitrage/client.rb +48 -0
  18. data/lib/rbtc_arbitrage/clients/btce_client.rb +62 -0
  19. data/lib/rbtc_arbitrage/clients/campbx_client.rb +48 -0
  20. data/lib/rbtc_arbitrage/clients/client.rb.example +46 -0
  21. data/lib/rbtc_arbitrage/clients/coinbase_client.rb +63 -0
  22. data/lib/rbtc_arbitrage/clients/mtgox_client.rb +56 -0
  23. data/lib/rbtc_arbitrage/trader.rb +123 -0
  24. data/lib/rbtc_arbitrage/version.rb +3 -0
  25. data/rbtc_arbitrage.gemspec +30 -0
  26. data/spec/cli_spec.rb +8 -0
  27. data/spec/client_spec.rb +33 -0
  28. data/spec/clients/btce_client_spec.rb +93 -0
  29. data/spec/clients/campbx_client_spec.rb +66 -0
  30. data/spec/clients/coinbase_client_spec.rb +66 -0
  31. data/spec/clients/mtgox_client_spec.rb +53 -0
  32. data/spec/rbtc_arbitrage_spec.rb +11 -0
  33. data/spec/spec_helper.rb +34 -0
  34. data/spec/support/cassettes/RbtcArbitrage_Clients_BitstampClient/_balance/fetches_the_balance_correctly.yml +96 -0
  35. data/spec/support/cassettes/RbtcArbitrage_Clients_BitstampClient/_price/fetches_price_for_buy_correctly.yml +52 -0
  36. data/spec/support/cassettes/RbtcArbitrage_Clients_BitstampClient/_price/fetches_price_for_sell_correctly.yml +52 -0
  37. data/spec/support/cassettes/RbtcArbitrage_Clients_BitstampClient/_price/fetches_prices_correctly.yml +44 -0
  38. data/spec/support/cassettes/RbtcArbitrage_Clients_BtceClient/_balance/should_raise_if_bad_API_keys.yml +53 -0
  39. data/spec/support/cassettes/RbtcArbitrage_Clients_BtceClient/_price/calls_btc-e.yml +91 -0
  40. data/spec/support/cassettes/RbtcArbitrage_Clients_BtceClient/_price/fetches_price_for_buy_correctly.yml +47 -0
  41. data/spec/support/cassettes/RbtcArbitrage_Clients_BtceClient/_price/fetches_price_for_sell_correctly.yml +47 -0
  42. data/spec/support/cassettes/RbtcArbitrage_Clients_CampbxClient/_balance/fetches_the_balance_correctly.yml +95 -0
  43. data/spec/support/cassettes/RbtcArbitrage_Clients_CampbxClient/_price/fetches_price_for_buy_correctly.yml +49 -0
  44. data/spec/support/cassettes/RbtcArbitrage_Clients_CampbxClient/_price/fetches_price_for_sell_correctly.yml +49 -0
  45. data/spec/support/cassettes/RbtcArbitrage_Clients_CoinbaseClient/_balance/fetches_the_balance_correctly.yml +109 -0
  46. data/spec/support/cassettes/RbtcArbitrage_Clients_CoinbaseClient/_price/calls_coinbase.yml +215 -0
  47. data/spec/support/cassettes/RbtcArbitrage_Clients_CoinbaseClient/_price/fetches_price_for_buy_correctly.yml +56 -0
  48. data/spec/support/cassettes/RbtcArbitrage_Clients_CoinbaseClient/_price/fetches_price_for_sell_correctly.yml +56 -0
  49. data/spec/support/cassettes/RbtcArbitrage_Clients_MtGoxClient/_balance/fetches_the_balance_correctly.yml +77 -0
  50. data/spec/support/cassettes/RbtcArbitrage_Clients_MtGoxClient/_price/fetches_price_for_buy_correctly.yml +44 -0
  51. data/spec/support/cassettes/RbtcArbitrage_Clients_MtGoxClient/_price/fetches_price_for_sell_correctly.yml +44 -0
  52. data/spec/support/cassettes/RbtcArbitrage_Clients_MtGoxClient/_price/fetches_prices_correctly.yml +85 -0
  53. data/spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/should_raise_SecurityError_if_not_live.yml +88 -0
  54. data/spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/when_live/raises_SecurityError_if_not_enough_BTC.yml +81 -0
  55. data/spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/when_live/raises_SecurityError_if_not_enough_USD.yml +81 -0
  56. data/spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/when_live/should_fetch_balance.yml +88 -0
  57. data/spec/support/cassettes/RbtcArbitrage_Trader/_execute_trade/when_live/shouldn_t_raise_security_error.yml +166 -0
  58. data/spec/support/cassettes/RbtcArbitrage_Trader/_fetch_prices/gets_the_right_price_set.yml +173 -0
  59. data/spec/trader_spec.rb +228 -0
  60. metadata +249 -0
@@ -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
@@ -0,0 +1,16 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ InstalledFiles
7
+ _yardoc
8
+ coverage
9
+ doc/
10
+ lib/bundler/man
11
+ pkg
12
+ rdoc
13
+ spec/reports
14
+ test/tmp
15
+ test/version_tmp
16
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format d
@@ -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'
@@ -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
@@ -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
+
@@ -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.
@@ -0,0 +1 @@
1
+ web: bundle exec ruby dummy_web_server.rb -p $PORT
@@ -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.
@@ -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
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rbtc_arbitrage'
4
+ RbtcArbitrage::CLI.start ARGV
@@ -0,0 +1,9 @@
1
+ # This is a dummy web server that will
2
+ # make it easy for us to run ruby
3
+ # scripts on Heroku.
4
+
5
+ require 'sinatra'
6
+
7
+ get '/' do
8
+ "Hello, world"
9
+ end
@@ -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