rbtc_arbitrage_simple 1.2.3

Sign up to get free protection for your applications and to get access to all the features.
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