mt_gox 0.7.3

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,46 @@
1
+ !.gitignore
2
+ *.gem
3
+ *.rbc
4
+ *.sw[a-p]
5
+ *.tmproj
6
+ *.tmproject
7
+ *.un~
8
+ *~
9
+ .DS_Store
10
+ .Spotlight-V100
11
+ .Trashes
12
+ ._*
13
+ .bundle
14
+ .config
15
+ .directory
16
+ .elc
17
+ .redcar
18
+ .yardoc
19
+ /.emacs.desktop
20
+ /.emacs.desktop.lock
21
+ Desktop.ini
22
+ Gemfile.lock
23
+ Icon?
24
+ InstalledFiles
25
+ Session.vim
26
+ Thumbs.db
27
+ \#*\#
28
+ _yardoc
29
+ auto-save-list
30
+ coverage
31
+ doc/
32
+ lib/bundler/man
33
+ pkg
34
+ pkg/*
35
+ rdoc
36
+ spec/reports
37
+ test/tmp
38
+ test/version_tmp
39
+ tmp
40
+ tmtags
41
+ tramp
42
+
43
+ ## Idea
44
+ .idea
45
+ .rakeTasks
46
+ *.iml
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --order random
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.9.2
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ rvm:
2
+ - 1.9.2
3
+ - 1.9.3
data/.yardopts ADDED
@@ -0,0 +1,4 @@
1
+ --tag authenticated:"Requires Authentication"
2
+ --markup markdown
3
+ -
4
+ LICENSE.md
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE.md ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Erik Michaels-Ober
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # Ruby wrapper for the Mt. Gox Trade API.
2
+
3
+
4
+ ## <a name="fork"></a>This Fork
5
+ This is a fork of https://github.com/sferik/mtgox. This fork features a rework of the
6
+ original business domain entities into new Models, with an intent to make these Models
7
+ ActiveModel-compliant in future.
8
+
9
+ ## <a name="installation"></a>Installation
10
+ gem install mt_gox
11
+
12
+ ## <a name="alias"></a>Alias
13
+ After installing the gem, you can get the current price for 1 BTC in USD by
14
+ typing `btc` in your bash shell simply by setting the following alias:
15
+
16
+ alias btc='ruby -r rubygems -r mtgox -e "puts MtGox.ticker.sell"'
17
+
18
+ ## <a name="examples"></a>Usage Examples
19
+ require 'rubygems'
20
+ require 'mtgox'
21
+
22
+ # Fetch the latest price for 1 BTC in USD
23
+ puts MtGox.ticker.sell
24
+
25
+ # Fetch open asks
26
+ puts MtGox.asks
27
+
28
+ # Fetch open bids
29
+ puts MtGox.bids
30
+
31
+ # Fetch the last 48 hours worth of trades (takes a minute)
32
+ puts MtGox.trades
33
+
34
+ # Certain methods require authentication
35
+ MtGox.configure do |config|
36
+ config.key = YOUR_MTGOX_KEY
37
+ config.secret = YOUR_MTGOX_SECRET
38
+ end
39
+
40
+ # Fetch your current balance
41
+ puts MtGox.balance
42
+
43
+ # Place a limit order to buy one bitcoin for $0.011
44
+ MtGox.buy! 1.0, 0.011
45
+
46
+ # Place a limit order to sell one bitcoin for $100
47
+ MtGox.sell! 1.0, 100.0
48
+
49
+ # Cancel order #1234567890
50
+ MtGox.cancel 1234567890
51
+
52
+ # Withdraw 1 BTC from your account
53
+ MtGox.withdraw! 1.0, "1KxSo9bGBfPVFEtWNLpnUK1bfLNNT4q31L"
54
+
55
+ [issues]: https://github.com/arvicco/mtgox/issues
56
+
57
+ ## <a name="copyright"></a>Copyright
58
+ Copyright (c) 2011 Erik Michaels-Ober.
59
+ Copyright (c) 2012 Arvicco (extensions).
60
+
61
+ See [LICENSE][] for details.
62
+
63
+ [license]: https://github.com/sferik/mtgox/blob/master/LICENSE.md
data/Rakefile ADDED
@@ -0,0 +1,38 @@
1
+ begin
2
+ require 'rake'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ gem 'rake', '~> 0.8.3.1'
6
+ require 'rake'
7
+ end
8
+
9
+ require 'pathname'
10
+
11
+ BASE_PATH = Pathname.new(__FILE__).dirname
12
+ LIB_PATH = BASE_PATH + 'lib'
13
+ PKG_PATH = BASE_PATH + 'pkg'
14
+ DOC_PATH = BASE_PATH + 'rdoc'
15
+
16
+ $LOAD_PATH.unshift LIB_PATH.to_s
17
+ require 'mtgox/version'
18
+
19
+ NAME = 'mt_gox'
20
+ CLASS_NAME = MtGox
21
+
22
+ # Load rakefile tasks
23
+ Dir['tasks/*.rake'].sort.each { |file| load file }
24
+
25
+
26
+ # Project-specific tasks
27
+
28
+ require 'yard'
29
+ namespace :doc do
30
+ YARD::Rake::YardocTask.new do |task|
31
+ task.files = ['LICENSE.md', 'lib/**/*.rb']
32
+ task.options = [
33
+ '--tag', 'authenticated:Requires Authentication',
34
+ '--markup', 'markdown',
35
+ ]
36
+ end
37
+ end
38
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.7.3
@@ -0,0 +1,11 @@
1
+ require 'faraday'
2
+
3
+ module Faraday
4
+ class Response::RaiseMtGoxError < Response::Middleware
5
+ def on_complete(env)
6
+ if 200 == env[:status] && 'MySQL error, please retry later' == env[:body]
7
+ raise MtGox::MysqlError, "MySQL error, please retry later"
8
+ end
9
+ end
10
+ end
11
+ end
data/lib/mtgox/ask.rb ADDED
@@ -0,0 +1,16 @@
1
+ require 'mtgox/offer'
2
+
3
+ module MtGox
4
+ class Ask < Offer
5
+
6
+ def initialize(price=nil, amount=nil)
7
+ self.price = price.to_f
8
+ self.amount = amount.to_f
9
+ end
10
+
11
+ def eprice
12
+ price / (1 - MtGox.commission)
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,10 @@
1
+ module MtGox
2
+ class Balance
3
+ attr_accessor :currency, :amount
4
+
5
+ def initialize(currency=nil, amount=nil)
6
+ self.currency = currency.to_s.upcase
7
+ self.amount = amount.to_f
8
+ end
9
+ end
10
+ end
data/lib/mtgox/bid.rb ADDED
@@ -0,0 +1,16 @@
1
+ require 'mtgox/offer'
2
+
3
+ module MtGox
4
+ class Bid < Offer
5
+
6
+ def initialize(price=nil, amount=nil)
7
+ self.price = price.to_f
8
+ self.amount = amount.to_f
9
+ end
10
+
11
+ def eprice
12
+ price * (1 - MtGox.commission)
13
+ end
14
+
15
+ end
16
+ end
data/lib/mtgox/buy.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'mtgox/order'
2
+
3
+ module MtGox
4
+ class Buy < Order
5
+ end
6
+ end
@@ -0,0 +1,263 @@
1
+ require 'faraday/error'
2
+ require 'mtgox/ask'
3
+ require 'mtgox/balance'
4
+ require 'mtgox/bid'
5
+ require 'mtgox/buy'
6
+ require 'mtgox/connection'
7
+ require 'mtgox/max_bid'
8
+ require 'mtgox/min_ask'
9
+ require 'mtgox/request'
10
+ require 'mtgox/sell'
11
+ require 'mtgox/ticker'
12
+ require 'mtgox/trade'
13
+
14
+ module MtGox
15
+ class Client
16
+ include MtGox::Connection
17
+ include MtGox::Request
18
+
19
+ ORDER_TYPES = {:sell => 1, :buy => 2}
20
+
21
+ # Fetch a deposit address
22
+ # @authenticated true
23
+ # @return [String]
24
+ # @example
25
+ # MtGox.address
26
+ def address
27
+ post('/api/0/btcAddress.php')['addr']
28
+ end
29
+
30
+
31
+ # Fetch the latest ticker data
32
+ #
33
+ # @authenticated false
34
+ # @return [MtGox::Ticker]
35
+ # @example
36
+ # MtGox.ticker
37
+ def ticker
38
+ ticker = get('/api/0/data/ticker.php')['ticker']
39
+ Ticker.instance.buy = ticker['buy'].to_f
40
+ Ticker.instance.high = ticker['high'].to_f
41
+ Ticker.instance.price = ticker['last'].to_f
42
+ Ticker.instance.low = ticker['low'].to_f
43
+ Ticker.instance.sell = ticker['sell'].to_f
44
+ Ticker.instance.volume = ticker['vol'].to_f
45
+ Ticker.instance.vwap = ticker['vwap'].to_f
46
+ Ticker.instance
47
+ end
48
+
49
+ # Fetch both bids and asks in one call, for network efficiency
50
+ #
51
+ # @authenticated false
52
+ # @return [Hash] with keys :asks and :asks, which contain arrays as described in {MtGox::Client#asks} and {MtGox::Clients#bids}
53
+ # @example
54
+ # MtGox.offers
55
+ def offers
56
+ offers = get('/api/0/data/getDepth.php')
57
+ asks = offers['asks'].sort_by do |ask|
58
+ ask[0].to_f
59
+ end.map! do |ask|
60
+ Ask.new(*ask)
61
+ end
62
+ bids = offers['bids'].sort_by do |bid|
63
+ -bid[0].to_f
64
+ end.map! do |bid|
65
+ Bid.new(*bid)
66
+ end
67
+ {:asks => asks, :bids => bids}
68
+ end
69
+
70
+ # Fetch open asks
71
+ #
72
+ # @authenticated false
73
+ # @return [Array<MtGox::Ask>] an array of open asks, sorted in price ascending order
74
+ # @example
75
+ # MtGox.asks
76
+ def asks
77
+ offers[:asks]
78
+ end
79
+
80
+ # Fetch open bids
81
+ #
82
+ # @authenticated false
83
+ # @return [Array<MtGox::Bid>] an array of open bids, sorted in price descending order
84
+ # @example
85
+ # MtGox.bids
86
+ def bids
87
+ offers[:bids]
88
+ end
89
+
90
+ # Fetch the lowest priced ask
91
+ #
92
+ # @authenticated false
93
+ # @return [MtGox::MinAsk]
94
+ # @example
95
+ # MtGox.min_ask
96
+ def min_ask
97
+ min_ask = asks.first
98
+ MinAsk.instance.price = min_ask.price
99
+ MinAsk.instance.amount = min_ask.amount
100
+ MinAsk.instance
101
+ end
102
+
103
+ # Fetch the highest priced bid
104
+ #
105
+ # @authenticated false
106
+ # @return [MtGox::MinBid]
107
+ # @example
108
+ # MtGox.max_bid
109
+ def max_bid
110
+ max_bid = bids.first
111
+ MaxBid.instance.price = max_bid.price
112
+ MaxBid.instance.amount = max_bid.amount
113
+ MaxBid.instance
114
+ end
115
+
116
+ # Fetch recent trades
117
+ #
118
+ # @authenticated false
119
+ # @return [Array<MtGox::Trade>] an array of trades, sorted in chronological order
120
+ # @example
121
+ # MtGox.trades
122
+ def trades
123
+ get('/api/0/data/getTrades.php').sort_by{|trade| trade['date']}.map do |trade|
124
+ Trade.new(trade)
125
+ end
126
+ end
127
+
128
+ # Fetch your current balance
129
+ #
130
+ # @authenticated true
131
+ # @return [Array<MtGox::Balance>]
132
+ # @example
133
+ # MtGox.balance
134
+ def balance
135
+ parse_balance(post('/api/0/getFunds.php', {}))
136
+ end
137
+
138
+ # Fetch your open orders, both buys and sells, for network efficiency
139
+ #
140
+ # @authenticated true
141
+ # @return [Hash] with keys :buys and :sells, which contain arrays as described in {MtGox::Client#buys} and {MtGox::Clients#sells}
142
+ # @example
143
+ # MtGox.orders
144
+ def orders
145
+ parse_orders(post('/api/0/getOrders.php', {})['orders'])
146
+ end
147
+
148
+ # Fetch your open buys
149
+ #
150
+ # @authenticated true
151
+ # @return [Array<MtGox::Buy>] an array of your open bids, sorted by date
152
+ # @example
153
+ # MtGox.buys
154
+ def buys
155
+ orders[:buys]
156
+ end
157
+
158
+ # Fetch your open sells
159
+ #
160
+ # @authenticated true
161
+ # @return [Array<MtGox::Sell>] an array of your open asks, sorted by date
162
+ # @example
163
+ # MtGox.sells
164
+ def sells
165
+ orders[:sells]
166
+ end
167
+
168
+ # Place a limit order to buy BTC
169
+ #
170
+ # @authenticated true
171
+ # @param amount [Numeric] the number of bitcoins to purchase
172
+ # @param price [Numeric] the bid price in US dollars
173
+ # @return [Hash] with keys :buys and :sells, which contain arrays as described in {MtGox::Client#buys} and {MtGox::Clients#sells}
174
+ # @example
175
+ # # Buy one bitcoin for $0.011
176
+ # MtGox.buy! 1.0, 0.011
177
+ def buy!(amount, price)
178
+ parse_orders(post('/api/0/buyBTC.php', {:amount => amount, :price => price})['orders'])
179
+ end
180
+
181
+ # Place a limit order to sell BTC
182
+ #
183
+ # @authenticated true
184
+ # @param amount [Numeric] the number of bitcoins to sell
185
+ # @param price [Numeric] the ask price in US dollars
186
+ # @return [Hash] with keys :buys and :sells, which contain arrays as described in {MtGox::Client#buys} and {MtGox::Clients#sells}
187
+ # @example
188
+ # # Sell one bitcoin for $100
189
+ # MtGox.sell! 1.0, 100.0
190
+ def sell!(amount, price)
191
+ parse_orders(post('/api/0/sellBTC.php', {:amount => amount, :price => price})['orders'])
192
+ end
193
+
194
+ # Cancel an open order
195
+ #
196
+ # @authenticated true
197
+ # @overload cancel(oid)
198
+ # @param oid [String] an order ID
199
+ # @return [Hash] with keys :buys and :sells, which contain arrays as described in {MtGox::Client#buys} and {MtGox::Clients#sells}
200
+ # @example
201
+ # my_order = MtGox.orders.first
202
+ # MtGox.cancel my_order.oid
203
+ # MtGox.cancel 1234567890
204
+ # @overload cancel(order)
205
+ # @param order [Hash] a hash-like object, with keys `oid` - the order ID of the transaction to cancel and `type` - the type of order to cancel (`1` for sell or `2` for buy)
206
+ # @return [Hash] with keys :buys and :sells, which contain arrays as described in {MtGox::Client#buys} and {MtGox::Clients#sells}
207
+ # @example
208
+ # my_order = MtGox.orders.first
209
+ # MtGox.cancel my_order
210
+ # MtGox.cancel {'oid' => '1234567890', 'type' => 2}
211
+ def cancel(args)
212
+ if args.is_a?(Hash)
213
+ order = args.delete_if{|k, v| !['oid', 'type'].include?(k.to_s)}
214
+ parse_orders(post('/api/0/cancelOrder.php', order)['orders'])
215
+ else
216
+ orders = post('/api/0/getOrders.php', {})['orders']
217
+ order = orders.find{|order| order['oid'] == args.to_s}
218
+ if order
219
+ order = order.delete_if{|k, v| !['oid', 'type'].include?(k.to_s)}
220
+ parse_orders(post('/api/0/cancelOrder.php', order)['orders'])
221
+ else
222
+ raise Faraday::Error::ResourceNotFound, {:status => 404, :headers => {}, :body => 'Order not found.'}
223
+ end
224
+ end
225
+ end
226
+
227
+ # Transfer bitcoins from your Mt. Gox account into another account
228
+ #
229
+ # @authenticated true
230
+ # @param amount [Numeric] the number of bitcoins to withdraw
231
+ # @param btca [String] the bitcoin address to send to
232
+ # @return [Array<MtGox::Balance>]
233
+ # @example
234
+ # # Withdraw 1 BTC from your account
235
+ # MtGox.withdraw! 1.0, '1KxSo9bGBfPVFEtWNLpnUK1bfLNNT4q31L'
236
+ def withdraw!(amount, btca)
237
+ parse_balance(post('/api/0/withdraw.php', {:group1 => 'BTC', :amount => amount, :btca => btca}))
238
+ end
239
+
240
+ private
241
+
242
+ def parse_balance(balance)
243
+ balances = []
244
+ balances << Balance.new('BTC', balance['btcs'])
245
+ balances << Balance.new('USD', balance['usds'])
246
+ balances
247
+ end
248
+
249
+ def parse_orders(orders)
250
+ buys = []
251
+ sells = []
252
+ orders.sort_by{|order| order['date']}.each do |order|
253
+ case order['type']
254
+ when ORDER_TYPES[:sell]
255
+ sells << Sell.new(order)
256
+ when ORDER_TYPES[:buy]
257
+ buys << Buy.new(order)
258
+ end
259
+ end
260
+ {:buys => buys, :sells => sells}
261
+ end
262
+ end
263
+ end
@@ -0,0 +1,41 @@
1
+ require 'mtgox/version'
2
+
3
+ module MtGox
4
+ module Configuration
5
+ # An array of valid keys in the options hash when configuring a {MtGox::Client}
6
+ VALID_OPTIONS_KEYS = [
7
+ :commission,
8
+ :key,
9
+ :secret,
10
+ ]
11
+
12
+ DEFAULT_COMMISSION = 0.0065.freeze
13
+
14
+ attr_accessor *VALID_OPTIONS_KEYS
15
+
16
+ # When this module is extended, set all configuration options to their default values
17
+ def self.extended(base)
18
+ base.reset
19
+ end
20
+
21
+ # Convenience method to allow configuration options to be set in a block
22
+ def configure
23
+ yield self
24
+ end
25
+
26
+ # Create a hash of options and their values
27
+ def options
28
+ options = {}
29
+ VALID_OPTIONS_KEYS.each{|k| options[k] = send(k)}
30
+ options
31
+ end
32
+
33
+ # Reset all configuration options to defaults
34
+ def reset
35
+ self.commission = DEFAULT_COMMISSION
36
+ self.key = nil
37
+ self.secret = nil
38
+ self
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,32 @@
1
+ require 'faraday'
2
+ require 'faraday/request/url_encoded'
3
+ require 'faraday/response/raise_error'
4
+ require 'faraday/response/parse_json'
5
+ require 'faraday/response/raise_mtgox_error'
6
+ require 'faraday_middleware'
7
+ require 'mtgox/version'
8
+
9
+ module MtGox
10
+ module Connection
11
+ private
12
+
13
+ def connection
14
+ options = {
15
+ :headers => {
16
+ :accept => 'application/json',
17
+ :user_agent => "mt_gox gem #{MtGox::VERSION}",
18
+ },
19
+ :ssl => {:verify => false},
20
+ :url => 'https://mtgox.com',
21
+ }
22
+
23
+ Faraday.new(options) do |connection|
24
+ connection.use Faraday::Request::UrlEncoded
25
+ connection.use Faraday::Response::RaiseError
26
+ connection.use Faraday::Response::ParseJson
27
+ connection.use Faraday::Response::RaiseMtGoxError
28
+ connection.adapter(Faraday.default_adapter)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,7 @@
1
+ module MtGox
2
+ # Custom error class for rescuing from all MtGox errors
3
+ class Error < StandardError; end
4
+
5
+ class MysqlError < Error; end
6
+ end
7
+
@@ -0,0 +1,10 @@
1
+ require 'mtgox/bid'
2
+ require 'mtgox/price_ticker'
3
+ require 'singleton'
4
+
5
+ module MtGox
6
+ class MaxBid < Bid
7
+ include Singleton
8
+ include PriceTicker
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ require 'mtgox/ask'
2
+ require 'mtgox/price_ticker'
3
+ require 'singleton'
4
+
5
+ module MtGox
6
+ class MinAsk < Ask
7
+ include Singleton
8
+ include PriceTicker
9
+ end
10
+ end
@@ -0,0 +1,5 @@
1
+ module MtGox
2
+ class Offer
3
+ attr_accessor :amount, :price
4
+ end
5
+ end
@@ -0,0 +1,14 @@
1
+ require 'mtgox/offer'
2
+
3
+ module MtGox
4
+ class Order < Offer
5
+ attr_accessor :id, :date
6
+
7
+ def initialize(order={})
8
+ self.id = order['oid']
9
+ self.date = Time.at(order['date'].to_i)
10
+ self.amount = order['amount'].to_f
11
+ self.price = order['price'].to_f
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,27 @@
1
+ module MtGox
2
+ module PriceTicker
3
+ attr_reader :previous_price, :price
4
+
5
+ def price=(price)
6
+ @previous_price = @price
7
+ @price = price
8
+ end
9
+
10
+ def up?
11
+ price.to_f > previous_price.to_f
12
+ end
13
+
14
+ def down?
15
+ price.to_f < previous_price.to_f
16
+ end
17
+
18
+ def changed?
19
+ price.to_f != previous_price.to_f
20
+ end
21
+
22
+ def unchanged?
23
+ !changed?
24
+ end
25
+ alias :unch? :unchanged?
26
+ end
27
+ end