lib/mtgox/client.rb
require 'faraday/error'
require 'mtgox/ask'
require 'mtgox/balance'
require 'mtgox/bid'
require 'mtgox/buy'
require 'mtgox/connection'
require 'mtgox/max_bid'
require 'mtgox/min_ask'
require 'mtgox/request'
require 'mtgox/sell'
require 'mtgox/ticker'
require 'mtgox/trade'
require 'mtgox/value'
require 'mtgox/lag'
require 'mtgox/configuration'
require 'mtgox/order_result'
module MtGox
class Client # rubocop:disable ClassLength
include MtGox::Connection
include MtGox::Request
include MtGox::Value
include MtGox::Configuration
ORDER_TYPES = {:sell => 'ask', :buy => 'bid'}
def initialize
reset
end
# Fetch a deposit address
# @authenticated true
# @return [String]
# @example
# MtGox.address
def address
post('/api/1/generic/bitcoin/address')['addr']
end
# Get an idKey for subscribing to private channels in WebSocket API
# @authenticated true
# @return [String] the idKey to use in your WebSocket client
# @example
# MtGox.idkey
def idkey
post('/api/1/generic/idkey')
end
# Fetch the latest ticker data
#
# @authenticated false
# @return [MtGox::Ticker]
# @example
# MtGox.ticker
def ticker
ticker = get('/api/1/BTCUSD/ticker')
Ticker.instance.buy = value_currency ticker['buy']
Ticker.instance.high = value_currency ticker['high']
Ticker.instance.price = value_currency ticker['last_all']
Ticker.instance.low = value_currency ticker['low']
Ticker.instance.sell = value_currency ticker['sell']
Ticker.instance.volume = value_bitcoin ticker['vol']
Ticker.instance.vwap = value_currency ticker['vwap']
Ticker.instance.avg = value_currency ticker['avg']
Ticker.instance.last_local = value_currency ticker['last_local']
Ticker.instance
end
# Fetch the latest lag data
#
# @authenticated false
# @return [MtGox::Lag]
# @example
# MtGox.lag
def lag
lag = get('/api/1/generic/order/lag')
Lag.new(lag['lag'], lag['lag_secs'], lag['lag_text'], lag['length'])
end
alias_method :order_lag, :lag
alias_method :orderlag, :lag
# Fetch both bids and asks in one call, for network efficiency
#
# @authenticated false
# @return [Hash] with keys :asks and :bids, which contain arrays as described in {MtGox::Client#asks} and {MtGox::Clients#bids}
# @example
# MtGox.offers
def offers
offers = get('/api/1/BTCUSD/depth/fetch')
asks = offers['asks'].sort_by { |ask| ask['price_int'].to_i }.collect { |ask| Ask.new(self, ask) }
bids = offers['bids'].sort_by { |bid| -bid['price_int'].to_i }.collect { |bid| Bid.new(self, bid) }
{:asks => asks, :bids => bids}
end
# Fetch open asks
#
# @authenticated false
# @return [Array<MtGox::Ask>] an array of open asks, sorted in price ascending order
# @example
# MtGox.asks
def asks
offers[:asks]
end
# Fetch open bids
#
# @authenticated false
# @return [Array<MtGox::Bid>] an array of open bids, sorted in price descending order
# @example
# MtGox.bids
def bids
offers[:bids]
end
# Fetch the lowest priced ask
#
# @authenticated false
# @return [MtGox::MinAsk]
# @example
# MtGox.min_ask
def min_ask
asks.first
end
# Fetch the highest priced bid
#
# @authenticated false
# @return [MtGox::MinBid]
# @example
# MtGox.max_bid
def max_bid
bids.first
end
# Fetch recent trades
#
# @authenticated false
# @return [Array<MtGox::Trade>] an array of trades, sorted in chronological order
# @example
# MtGox.trades
# MtGox.trades :since => 12341234
def trades(opts = {})
get('/api/1/BTCUSD/trades/fetch', opts).
sort_by { |trade| trade['date'] }.collect do |trade|
Trade.new(trade)
end
end
# Fetch API rights
#
# @authenticated true
# @return [Array<String>] an array of strings
# @example
# MtGox.rights
def rights
post('/api/1/generic/info')['Rights']
end
# Fetch your current balance
#
# @authenticated true
# @return [Array<MtGox::Balance>]
# @example
# MtGox.balance
def balance
parse_balance(post('/api/1/generic/info'))
end
# Fetch your open orders, both buys and sells, for network efficiency
#
# @authenticated true
# @return [Hash] with keys :buys and :sells, which contain arrays as described in {MtGox::Client#buys} and {MtGox::Clients#sells}
# @example
# MtGox.orders
def orders
parse_orders(post('/api/1/generic/orders'))
end
# Fetch your open buys
#
# @authenticated true
# @return [Array<MtGox::Buy>] an array of your open bids, sorted by date
# @example
# MtGox.buys
def buys
orders[:buys]
end
# Fetch your open sells
#
# @authenticated true
# @return [Array<MtGox::Sell>] an array of your open asks, sorted by date
# @example
# MtGox.sells
def sells
orders[:sells]
end
# Place a limit order to buy BTC
#
# @authenticated true
# @param amount [Numeric] the number of bitcoins to purchase
# @param price [Numeric or Symbol] the bid price in US dollars, or :market if placing a market order
# @return [String] order ID for the buy, can be inspected using order_result
# @example
# # Buy one bitcoin for $0.011
# MtGox.buy! 1.0, 0.011
def buy!(amount, price)
add_order!(:buy, amount, price)
end
# Place a limit order to sell BTC
#
# @authenticated true
# @param amount [Numeric] the number of bitcoins to sell
# @param price [Numeric or Symbol] the ask price in US dollars, or :market if placing a market order
# @return [String] order ID for the sell, can be inspected using order_result
# @example
# # Sell one bitcoin for $100
# MtGox.sell! 1.0, 100.0
def sell!(amount, price)
add_order!(:sell, amount, price)
end
# Create a new order
#
# @authenticated true
# @param type [String] the type of order to create, either "buy" or "sell"
# @param amount [Numberic] the number of bitcoins to buy/sell
# @param price [Numeric or Symbol] the bid/ask price in USD, or :market if placing a market order
# @return [String] order ID for the order, can be inspected using order_result
# @example
# # Sell one bitcoin for $123
# MtGox.add_order! :sell, 1.0, 123.0
def order!(type, amount, price)
order = {:type => order_type(type), :amount_int => intify(amount, :btc)}
order[:price_int] = intify(price, :usd) if price != :market
post('/api/1/BTCUSD/order/add', order)
end
alias_method :add_order!, :order!
alias_method :addorder!, :order!
# Cancel an open order
#
# @authenticated true
# @overload cancel(oid)
# @param oid [String] an order ID
# @return [Hash] with keys :buys and :sells, which contain arrays as described in {MtGox::Client#buys} and {MtGox::Clients#sells}
# @example
# my_order = MtGox.orders.first
# MtGox.cancel my_order.oid
# MtGox.cancel 1234567890
# @overload cancel(order)
# @param order [Hash] a hash-like object, containing at least a key `oid` - the order ID of the transaction to cancel
# @return [Hash] with keys :buys and :sells, which contain arrays as described in {MtGox::Client#buys} and {MtGox::Clients#sells}
# @example
# my_order = MtGox.orders.first
# MtGox.cancel my_order
# MtGox.cancel {'oid' => '1234567890'}
def cancel(args)
args = args['oid'] if args.is_a?(Hash)
orders = post('/api/1/generic/orders')
order = orders.detect { |o| o['oid'] == args.to_s }
if order
res = post('/api/1/BTCUSD/order/cancel', :oid => order['oid'])
orders.delete_if { |o| o['oid'] == res['oid'] }
parse_orders(orders)
else
fail(MtGox::OrderNotFoundError)
end
end
alias_method :cancel_order, :cancel
alias_method :cancelorder, :cancel
# Transfer bitcoins from your Mt. Gox account into another account
#
# @authenticated true
# @param amount [Numeric] the number of bitcoins to withdraw
# @param address [String] the bitcoin address to send to
# @return [String] Completed Transaction ID
# @example
# # Withdraw 1 BTC from your account
# MtGox.withdraw! 1.0, '1KxSo9bGBfPVFEtWNLpnUK1bfLNNT4q31L'
def withdraw!(amount, address)
if amount >= 1000
fail(FilthyRichError.new("#withdraw! take bitcoin amount as parameter (you are trying to withdraw #{amount} BTC"))
else
post('/api/1/generic/bitcoin/send_simple', :amount_int => intify(amount, :btc), :address => address)['trx']
end
end
# Fetch wallet history
#
# @authenticated true
# @param currency [String] 'USD', 'BTC'
# @param params [Hash] optional hash with type, date_start, date_end,
# trade_id, page
# @see https://en.bitcoin.it/wiki/MtGox/API/HTTP/v1#Your_wallet_history
def history(currency, params = {})
post('/api/1/generic/wallet/history', params.merge(:currency => currency))
end
# Fetch information about a particular transaction
#
# @authenticated true
# @param offer_type [String] 'bid' or 'ask'
# @param order_id [String] the order id
# @return [OrderResult]
def order_result(offer_type, order_id)
OrderResult.new(post('/api/1/generic/order/result', :type => offer_type, :order => order_id))
end
private
def parse_balance(info)
balances = []
info['Wallets'].each do |currency, wallet|
value = currency == 'BTC' ? value_bitcoin(wallet['Balance']) : value_currency(wallet['Balance'])
balances << Balance.new(currency, value)
end
balances
end
def parse_orders(orders)
buys = []
sells = []
orders.sort_by { |order| order['date'] }.each do |order|
case order['type']
when ORDER_TYPES[:sell]
sells << Sell.new(order)
when ORDER_TYPES[:buy]
buys << Buy.new(order)
end
end
{:buys => buys, :sells => sells}
end
def order_type(type)
if ORDER_TYPES.values.include?(type.to_s)
type
else
ORDER_TYPES[type.downcase.to_sym]
end
end
end
end