gemini-rb 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/gemini/api_versions.rb +7 -0
- data/lib/gemini/authenticated_rest.rb +58 -0
- data/lib/gemini/client.rb +38 -0
- data/lib/gemini/configurable.rb +48 -0
- data/lib/gemini/connection.rb +52 -0
- data/lib/gemini/errors.rb +35 -0
- data/lib/gemini/v1/account_info.rb +38 -0
- data/lib/gemini/v1/deposit.rb +23 -0
- data/lib/gemini/v1/funding_book.rb +18 -0
- data/lib/gemini/v1/historical_data.rb +53 -0
- data/lib/gemini/v1/lends.rb +18 -0
- data/lib/gemini/v1/margin_funding.rb +103 -0
- data/lib/gemini/v1/orderbook.rb +36 -0
- data/lib/gemini/v1/orders.rb +121 -0
- data/lib/gemini/v1/positions.rb +27 -0
- data/lib/gemini/v1/stats.rb +15 -0
- data/lib/gemini/v1/symbols.rb +22 -0
- data/lib/gemini/v1/ticker.rb +27 -0
- data/lib/gemini/v1/trades.rb +31 -0
- data/lib/gemini/v1/wallet.rb +98 -0
- data/lib/gemini/v2/margin.rb +34 -0
- data/lib/gemini/v2/personal.rb +94 -0
- data/lib/gemini/v2/stats.rb +27 -0
- data/lib/gemini/v2/ticker.rb +58 -0
- data/lib/gemini/v2/trading.rb +146 -0
- data/lib/gemini/v2/utils.rb +27 -0
- data/lib/gemini/version.rb +3 -0
- data/lib/gemini/websocket_connection.rb +231 -0
- data/lib/gemini-api-rb.rb +1 -0
- data/lib/gemini.rb +38 -0
- metadata +188 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f8b6bdb4c745a5e128399dc907263c45cc246494
|
4
|
+
data.tar.gz: 51b0da98bbe215bd3f98d97cf181b50eefc6fa92
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e58aad70668f996a1ed5eba5b50615c25a739601dce52bb86cd3bbdadde40d13cdb514d700af39cf4c80d56ab963ad32921a05b7f738b1f283df67c365ca3bf5
|
7
|
+
data.tar.gz: 773a41a59776f1702ba415555aa215e255fab65e85fdefaa0dad47c0d240ef35eb72837546cb832431993e68dd1afb7cc435b2b0dc01d497c092b0eb8a9f20e9
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Gemini
|
2
|
+
module AuthenticatedConnection
|
3
|
+
|
4
|
+
private
|
5
|
+
def authenticated_post(url, options = {})
|
6
|
+
raise Gemini::InvalidAuthKeyError unless valid_key?
|
7
|
+
complete_url = build_url(url)
|
8
|
+
body = options[:params] || {}
|
9
|
+
nonce = new_nonce
|
10
|
+
|
11
|
+
payload = if config.api_version == 1
|
12
|
+
build_payload("/v1/#{url}", options[:params], nonce)
|
13
|
+
else
|
14
|
+
"/api#{complete_url}#{nonce}#{body.to_json}"
|
15
|
+
end
|
16
|
+
|
17
|
+
response = rest_connection.post do |req|
|
18
|
+
req.url complete_url
|
19
|
+
req.body = body.to_json
|
20
|
+
req.options.timeout = config.rest_timeout
|
21
|
+
req.options.open_timeout = config.rest_open_timeout
|
22
|
+
req.headers['Content-Type'] = 'application/json'
|
23
|
+
req.headers['Accept'] = 'application/json'
|
24
|
+
|
25
|
+
if config.api_version == 1
|
26
|
+
req.headers['X-GEMINI-PAYLOAD'] = payload
|
27
|
+
req.headers['X-GEMINI-SIGNATURE'] = sign(payload)
|
28
|
+
req.headers['X-GEMINI-APIKEY'] = config.api_key
|
29
|
+
else
|
30
|
+
# TODO: Verify if this applies to Gemini.
|
31
|
+
req.headers['gemini-nonce'] = nonce
|
32
|
+
req.headers['gemini-signature'] = sign(payload)
|
33
|
+
req.headers['gemini-apikey'] = config.api_key
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def build_payload(url, params = {}, nonce)
|
39
|
+
payload = {}
|
40
|
+
payload['nonce'] = nonce
|
41
|
+
payload['request'] = url
|
42
|
+
payload.merge!(params) if params
|
43
|
+
Base64.strict_encode64(payload.to_json)
|
44
|
+
end
|
45
|
+
|
46
|
+
def new_nonce
|
47
|
+
(Time.now.to_f * 10_000).to_i.to_s
|
48
|
+
end
|
49
|
+
|
50
|
+
def sign(payload)
|
51
|
+
OpenSSL::HMAC.hexdigest('sha384', config.secret, payload)
|
52
|
+
end
|
53
|
+
|
54
|
+
def valid_key?
|
55
|
+
!! (config.api_key && config.secret)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Gemini
|
2
|
+
class Client
|
3
|
+
include Gemini::RestConnection
|
4
|
+
include Gemini::WebsocketConnection
|
5
|
+
include Gemini::AuthenticatedConnection
|
6
|
+
include Gemini::Configurable
|
7
|
+
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
if config.api_version == 1
|
11
|
+
extend Gemini::V1::TickerClient
|
12
|
+
extend Gemini::V1::TradesClient
|
13
|
+
extend Gemini::V1::FundingBookClient
|
14
|
+
extend Gemini::V1::OrderbookClient
|
15
|
+
extend Gemini::V1::StatsClient
|
16
|
+
extend Gemini::V1::LendsClient
|
17
|
+
extend Gemini::V1::SymbolsClient
|
18
|
+
extend Gemini::V1::AccountInfoClient
|
19
|
+
extend Gemini::V1::DepositClient
|
20
|
+
extend Gemini::V1::OrdersClient
|
21
|
+
extend Gemini::V1::PositionsClient
|
22
|
+
extend Gemini::V1::HistoricalDataClient
|
23
|
+
extend Gemini::V1::MarginFundingClient
|
24
|
+
extend Gemini::V1::WalletClient
|
25
|
+
else
|
26
|
+
extend Gemini::V2::TickerClient
|
27
|
+
extend Gemini::V2::StatsClient
|
28
|
+
extend Gemini::V2::UtilsClient
|
29
|
+
extend Gemini::V2::PersonalClient
|
30
|
+
extend Gemini::V2::TradingClient
|
31
|
+
extend Gemini::V2::MarginClient
|
32
|
+
end
|
33
|
+
|
34
|
+
@mutex = Mutex.new
|
35
|
+
@c_counter = 1
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Gemini
|
2
|
+
module Configurable
|
3
|
+
def self.included(base)
|
4
|
+
base.extend(ClassMethods)
|
5
|
+
end
|
6
|
+
|
7
|
+
def config
|
8
|
+
self.class.config
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def configure
|
13
|
+
yield config
|
14
|
+
end
|
15
|
+
|
16
|
+
def config
|
17
|
+
@configuration ||= Configuration.new
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Configuration
|
23
|
+
attr_accessor :api_endpoint, :debug, :debug_connection, :secret
|
24
|
+
attr_accessor :api_key, :websocket_api_endpoint, :rest_timeout
|
25
|
+
attr_accessor :reconnect, :reconnect_after, :rest_open_timeout
|
26
|
+
attr_accessor :api_version
|
27
|
+
|
28
|
+
def initialize
|
29
|
+
self.api_endpoint = "https://api.gemini.com/v1/"
|
30
|
+
self.websocket_api_endpoint = "wss://api.gemini.com/ws"
|
31
|
+
self.debug = false
|
32
|
+
self.reconnect = true
|
33
|
+
self.reconnect_after = 60
|
34
|
+
self.rest_timeout = 30
|
35
|
+
self.rest_open_timeout = 30
|
36
|
+
self.debug_connection = false
|
37
|
+
self.api_version = 1
|
38
|
+
end
|
39
|
+
|
40
|
+
# Helper that configure to version 2
|
41
|
+
def use_api_v2
|
42
|
+
self.api_version = 2
|
43
|
+
self.api_endpoint = "https://api.gemini.com/v2/"
|
44
|
+
self.websocket_api_endpoint = "wss://api.gemini.com/ws/2/"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'logger'
|
2
|
+
module Gemini
|
3
|
+
# Network Layer for API Rest client
|
4
|
+
module RestConnection
|
5
|
+
private
|
6
|
+
# Make an HTTP GET request
|
7
|
+
def get(url, params={})
|
8
|
+
rest_connection.get do |req|
|
9
|
+
req.url build_url(url)
|
10
|
+
req.headers['Content-Type'] = 'application/json'
|
11
|
+
req.headers['Accept'] = 'application/json'
|
12
|
+
params.each do |k,v|
|
13
|
+
req.params[k] = v
|
14
|
+
end
|
15
|
+
req.options.timeout = config.rest_timeout
|
16
|
+
req.options.open_timeout = config.rest_open_timeout
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Make sure parameters are allowed for the HTTP call
|
21
|
+
def check_params(params, allowed_params)
|
22
|
+
if (params.keys - allowed_params).empty?
|
23
|
+
return params
|
24
|
+
else
|
25
|
+
raise Gemini::ParamsError
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def rest_connection
|
30
|
+
@conn ||= new_rest_connection
|
31
|
+
end
|
32
|
+
|
33
|
+
def build_url(url)
|
34
|
+
URI.join(config.api_endpoint, url).path
|
35
|
+
end
|
36
|
+
|
37
|
+
def new_rest_connection
|
38
|
+
Faraday.new(url: base_api_endpoint) do |conn|
|
39
|
+
conn.use Gemini::CustomErrors
|
40
|
+
conn.response :logger, Logger.new(STDOUT) , bodies: true if config.debug_connection
|
41
|
+
conn.use FaradayMiddleware::ParseJson, :content_type => /\bjson$/
|
42
|
+
conn.adapter :net_http
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def base_api_endpoint
|
47
|
+
url = URI.parse config.api_endpoint
|
48
|
+
"#{url.scheme}://#{url.host}:#{url.port}"
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
|
3
|
+
module Gemini
|
4
|
+
class ClientError < Exception; end
|
5
|
+
class ParamsError < ClientError; end
|
6
|
+
class InvalidAuthKeyError < ClientError; end
|
7
|
+
class BlockMissingError < ParamsError; end
|
8
|
+
class ServerError < Exception; end # Error reported back by Binfinex server
|
9
|
+
class ConnectionClosed < Exception; end
|
10
|
+
class BadRequestError < ServerError; end
|
11
|
+
class NotFoundError < ServerError; end
|
12
|
+
class ForbiddenError < ServerError; end
|
13
|
+
class UnauthorizedError < ServerError; end
|
14
|
+
class InternalServerError < ServerError; end
|
15
|
+
class WebsocketError < ServerError; end
|
16
|
+
|
17
|
+
class CustomErrors < Faraday::Response::Middleware
|
18
|
+
def on_complete(env)
|
19
|
+
case env[:status]
|
20
|
+
when 400
|
21
|
+
raise BadRequestError, env.body['message']
|
22
|
+
when 401
|
23
|
+
raise UnauthorizedError, env.body['message']
|
24
|
+
when 403
|
25
|
+
raise ForbiddenError, env.body['message']
|
26
|
+
when 404
|
27
|
+
raise NotFoundError, env.body['message']
|
28
|
+
when 500
|
29
|
+
raise InternalServerError, env.body['message']
|
30
|
+
else
|
31
|
+
super
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Gemini
|
2
|
+
module V1::AccountInfoClient
|
3
|
+
|
4
|
+
# Get account information
|
5
|
+
#
|
6
|
+
# @return [Hash] your account information
|
7
|
+
# @example:
|
8
|
+
# client.account_info
|
9
|
+
def account_info
|
10
|
+
resp = authenticated_post("account_infos")
|
11
|
+
resp.body
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
# Call block passing all account related specific messages sent via websocket
|
16
|
+
#
|
17
|
+
# @param block [Block] The code to be executed when new message is received
|
18
|
+
# @example:
|
19
|
+
# client.listen_account do |message|
|
20
|
+
# puts message.inspect
|
21
|
+
# end
|
22
|
+
def listen_account(&block)
|
23
|
+
raise BlockMissingError unless block_given?
|
24
|
+
ws_auth(&block)
|
25
|
+
end
|
26
|
+
|
27
|
+
# See the fees applied to your withdrawals
|
28
|
+
#
|
29
|
+
# @return [Hash]
|
30
|
+
# @example:
|
31
|
+
# client.fees
|
32
|
+
def fees
|
33
|
+
resp = authenticated_post("fees")
|
34
|
+
resp.body
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Gemini
|
2
|
+
module V1::DepositClient
|
3
|
+
|
4
|
+
# Return your deposit address to make a new deposit.
|
5
|
+
#
|
6
|
+
# @param method [string] Method of deposit (methods accepted: “bitcoin”, “litecoin”, “darkcoin”, “mastercoin” (tethers)).
|
7
|
+
# @param wallet_name [string] Wallet to deposit in (accepted: “trading”, “exchange”, “deposit”). Your wallet needs to already exist
|
8
|
+
# @params renew [integer] (optional) Default is 0. If set to 1, will return a new unused deposit address
|
9
|
+
#
|
10
|
+
# @return [Hash] confirmation of your deposit
|
11
|
+
# @example:
|
12
|
+
# client.deposit("bitcoin", "exchange")
|
13
|
+
def deposit method, wallet_name, renew=0
|
14
|
+
params = {
|
15
|
+
method: method,
|
16
|
+
wallet_name: wallet_name,
|
17
|
+
renew: renew
|
18
|
+
}
|
19
|
+
|
20
|
+
authenticated_post("deposit/new", params: params).body
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Gemini
|
2
|
+
module V1::FundingBookClient
|
3
|
+
|
4
|
+
# Get the full margin funding book
|
5
|
+
|
6
|
+
# @param currency [string] (optional) Speficy the currency, default "USD"
|
7
|
+
# @param params :limit_bids [int] (optional) Limit the number of funding bids returned. May be 0 in which case the array of bids is empty.
|
8
|
+
# @param params :limit_asks [int] (optional) Limit the number of funding offers returned. May be 0 in which case the array of asks is empty.
|
9
|
+
# @return [Hash] of :bids and :asks arrays
|
10
|
+
# @example:
|
11
|
+
# client.funding_book
|
12
|
+
def funding_book(currency="usd", params = {})
|
13
|
+
check_params(params, %i{limit_bids limit_asks})
|
14
|
+
get("lendbook/#{currency}", params: params).body
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Gemini
|
2
|
+
module V1::HistoricalDataClient
|
3
|
+
|
4
|
+
# View all of your balance ledger entries.
|
5
|
+
#
|
6
|
+
# @param currency [string] (optional) Specify the currency, default "USD"
|
7
|
+
# @param params :since [time] (optional) Return only the history after this timestamp.
|
8
|
+
# @param params :until [time] (optional) Return only the history before this timestamp.
|
9
|
+
# @param params :limit [int] (optional) Limit the number of entries to return. Default is 500.
|
10
|
+
# @param params :wallet [string] (optional) Return only entries that took place in this wallet. Accepted inputs are: “trading”, “exchange”, “deposit”
|
11
|
+
# @return [Array]
|
12
|
+
# @example:
|
13
|
+
# client.history
|
14
|
+
def history(currency="usd", params = {})
|
15
|
+
check_params(params, %i{since until limit wallet})
|
16
|
+
params.merge!({currency: currency})
|
17
|
+
authenticated_post("history", params: params).body
|
18
|
+
end
|
19
|
+
|
20
|
+
# View your past deposits/withdrawals.
|
21
|
+
#
|
22
|
+
# @param currency [string] (optional) Specify the currency, default "USD"
|
23
|
+
# @param params :method (optional) The method of the deposit/withdrawal (can be “bitcoin”, “litecoin”, “darkcoin”, “wire”)
|
24
|
+
# @param params :since (optional) Return only the history after this timestamp
|
25
|
+
# @param params :until [time] (optional) Return only the history before this timestamp.
|
26
|
+
# @param params :limit [int] (optional) Limit the number of entries to return. Default is 500.
|
27
|
+
# @return [Array]
|
28
|
+
# @example:
|
29
|
+
# client.movements
|
30
|
+
def movements(currency="usd", params = {})
|
31
|
+
check_params(params, %i{method since until limit})
|
32
|
+
params.merge!({currency: currency})
|
33
|
+
authenticated_post("history/movements", params: params).body
|
34
|
+
end
|
35
|
+
|
36
|
+
# View your past trades.
|
37
|
+
#
|
38
|
+
# @param symbol The pair traded (BTCUSD, LTCUSD, LTCBTC)
|
39
|
+
# @param params :until [time] (optional) Return only the history before this timestamp.
|
40
|
+
# @param params :timestamp [time] (optional) Trades made before this timestamp won’t be returned
|
41
|
+
# @param params :until [time] (optional) Trades made after this timestamp won’t be returned
|
42
|
+
# @param params :limit_trades [int] Limit the number of trades returned. Default is 50.
|
43
|
+
# @param params :reverse [int] Return trades in reverse order (the oldest comes first). Default is returning newest trades first.
|
44
|
+
# @return [Array]
|
45
|
+
# @example:
|
46
|
+
# client.mytrades
|
47
|
+
def mytrades(symbol, params = {})
|
48
|
+
check_params(params, %i{until limit_trades reverse timestamp})
|
49
|
+
params.merge!({symbol: symbol})
|
50
|
+
authenticated_post("mytrades", params: params).body
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Gemini
|
2
|
+
module V1::LendsClient
|
3
|
+
|
4
|
+
# Get a list of the most recent funding data for the given currency: total amount provided and Flash Return Rate (in % by 365 days) over time.
|
5
|
+
#
|
6
|
+
# @param currency [string] (optional) Specify the currency, default "USD"
|
7
|
+
# @param params :timestamp [time] (optional) Only show data at or after this timestamp
|
8
|
+
# @param params :limit_lends [int] (optional) Limit the amount of funding data returned. Must be > 1, default 50
|
9
|
+
# @return [Array]
|
10
|
+
# @example:
|
11
|
+
# client.lends
|
12
|
+
def lends(currency = "usd", params = {})
|
13
|
+
check_params(params, %i{timestamp limit_lends})
|
14
|
+
get("lends/#{currency}", params: params).body
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module Gemini
|
2
|
+
module V1::MarginFundingClient
|
3
|
+
|
4
|
+
# Submit a new offer
|
5
|
+
#
|
6
|
+
# @param currency [string] The name of the currency, es: 'USD'
|
7
|
+
# @param amount [decimal] Offer size: how much to lend or borrow
|
8
|
+
# @param rate [decimal] Rate to lend or borrow at. In percentage per 365 days.
|
9
|
+
# Set to 0 for FRR, ±delta for FRR±delta.
|
10
|
+
# @param period [integer] Number of days of the funding contract (in days)
|
11
|
+
# @param direction [string] Either “lend” or “loan”
|
12
|
+
# @param frrdelta [bool] If true, the rate represents ±delta to FRR.
|
13
|
+
# @return [Hash]
|
14
|
+
# @example:
|
15
|
+
# client.new_offer("btc", 10.0, 20, 365, "lend")
|
16
|
+
def new_offer(currency, amount, rate, period, direction, frrdelta=false)
|
17
|
+
params = {
|
18
|
+
currency: currency,
|
19
|
+
amount: amount.to_s,
|
20
|
+
rate: rate.to_s,
|
21
|
+
period: period.to_i,
|
22
|
+
direction: direction,
|
23
|
+
frrdelta: !!frrdelta
|
24
|
+
}
|
25
|
+
authenticated_post("offer/new", params: params).body
|
26
|
+
end
|
27
|
+
|
28
|
+
# Cancel an offer
|
29
|
+
#
|
30
|
+
# @param offer_id [int] The offer ID given by `#new_offer`
|
31
|
+
# @return [Hash]
|
32
|
+
# @example:
|
33
|
+
# client.cancel_offer(1000)
|
34
|
+
def cancel_offer(offer_id)
|
35
|
+
authenticated_post("offer/cancel", params: {offer_id: offer_id.to_i}).body
|
36
|
+
end
|
37
|
+
|
38
|
+
# Get the status of an offer. Is it active? Was it cancelled? To what extent has it been executed? etc.
|
39
|
+
#
|
40
|
+
# @param offer_id [int] The offer ID give by `#new_offer`
|
41
|
+
# @return [Hash]
|
42
|
+
# @example:
|
43
|
+
# client.offer_status(1000)
|
44
|
+
def offer_status(offer_id)
|
45
|
+
authenticated_post("offer/status", params: {offer_id: offer_id.to_i}).body
|
46
|
+
end
|
47
|
+
|
48
|
+
# View your funds currently taken (active credits)
|
49
|
+
#
|
50
|
+
# @return [Array]
|
51
|
+
# @example:
|
52
|
+
# client.credits
|
53
|
+
def credits
|
54
|
+
authenticated_post("credits").body
|
55
|
+
end
|
56
|
+
|
57
|
+
# View your active offers
|
58
|
+
#
|
59
|
+
# @return [Array] An array of the results of /offer/status for all your live offers (lending or borrowing
|
60
|
+
# @example:
|
61
|
+
# client.offers
|
62
|
+
def offers
|
63
|
+
authenticated_post("offers").body
|
64
|
+
end
|
65
|
+
|
66
|
+
# View your funding currently borrowed and used in a margin position
|
67
|
+
#
|
68
|
+
# @return [Array] An array of your active margin funds
|
69
|
+
# @example:
|
70
|
+
# client.taken_funds
|
71
|
+
def taken_funds
|
72
|
+
authenticated_post("taken_funds").body
|
73
|
+
end
|
74
|
+
|
75
|
+
# View your funding currently borrowed and not used (available for a new margin position).
|
76
|
+
#
|
77
|
+
# @return [Array] An array of your active unused margin funds
|
78
|
+
# @example:
|
79
|
+
# client.unused_taken_funds
|
80
|
+
def unused_taken_funds
|
81
|
+
authenticated_post("unused_taken_funds").body
|
82
|
+
end
|
83
|
+
|
84
|
+
# View the total of your active funding used in your position(s).
|
85
|
+
#
|
86
|
+
# @return [Array] An array of your active funding
|
87
|
+
# @example:
|
88
|
+
# client.total_taken_funds
|
89
|
+
def total_taken_funds
|
90
|
+
authenticated_post("total_taken_funds").body
|
91
|
+
end
|
92
|
+
|
93
|
+
# Allow you to close an unused or used taken fund
|
94
|
+
#
|
95
|
+
# @param swap_id [int] The ID given by `#taken_funds` or `#unused_taken_funds
|
96
|
+
# @return [Hash]
|
97
|
+
# @example:
|
98
|
+
# client.close_funding(1000)
|
99
|
+
def close_funding(swap_id)
|
100
|
+
authenticated_post("funding/close", params: {swap_id: swap_id.to_i}).body
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module Gemini
|
3
|
+
module V1::OrderbookClient
|
4
|
+
|
5
|
+
# Get the full order book
|
6
|
+
#
|
7
|
+
# @param symbol [string]
|
8
|
+
# @param params :limit_bids [int] (optional) Limit the number of bids returned. May be 0 in which case the array of bids is empty. Default 50.
|
9
|
+
# @param params :limit_asks [int] (optional) Limit the number of asks returned. May be 0 in which case the array of asks is empty. Default 50.
|
10
|
+
# @param params :group [0/1] (optional) If 1, orders are grouped by price in the orderbook. If 0, orders are not grouped and sorted individually. Default 1
|
11
|
+
# @return [Hash] :bids [Array], :asks [Array]
|
12
|
+
# @example:
|
13
|
+
# client.orderbook("btcusd")
|
14
|
+
def orderbook(symbol="btcusd", params = {})
|
15
|
+
check_params(params, %i{limit_bids limit_asks group})
|
16
|
+
get("book/#{symbol}", params: params).body
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
# Get the order book changes using websocket
|
21
|
+
#
|
22
|
+
# @param pair [string]
|
23
|
+
# @param prec [string] Level of price aggregation (P0, P1, P2, P3). The default is P0.
|
24
|
+
# @param freq [string] Frequency of updates (F0, F1, F2, F3). F0=realtime / F1=2sec / F2=5sec / F3=10sec
|
25
|
+
# @param len [int] Number of price points (“25”, “100”) [default=“25”]
|
26
|
+
# @param block [Block] The code to be executed when a new order is submitted
|
27
|
+
# @example:
|
28
|
+
# client.listen_book do |order|
|
29
|
+
# puts order.inspect
|
30
|
+
# end
|
31
|
+
def listen_book(pair="BTCUSD", prec='P0', freq='F0',len=25, &block)
|
32
|
+
raise BlockMissingError unless block_given?
|
33
|
+
register_channel pair:pair, channel: 'book', prec: prec, freq: freq, len: len, &block
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
module Gemini
|
2
|
+
module V1::OrdersClient
|
3
|
+
|
4
|
+
# Submit a new order
|
5
|
+
# @param symbol [string] The name of the symbol (see `#symbols`)
|
6
|
+
# @param amount [decimal] Order size: how much to buy or sell
|
7
|
+
# @param type [string] Either “market” / “limit” / “stop” / “trailing-stop” / “fill-or-kill” / “exchange market” / “exchange limit” / “exchange stop” / “exchange trailing-stop” / “exchange fill-or-kill”. (type starting by “exchange ” are exchange orders, others are margin trading orders)
|
8
|
+
# @param side [string] Either “buy” or “sell”
|
9
|
+
# @param price [decimal] Price to buy or sell at. Must be positive. Use random number for market orders.
|
10
|
+
# @param params :is_hidden [bool] (optional) true if the order should be hidden. Default is false
|
11
|
+
# @param params :is_postonly [bool] (optional) true if the order should be post only. Default is false. Only relevant for limit orders
|
12
|
+
# @param params :ocoorder [bool] Set an additional STOP OCO order that will be linked with the current order
|
13
|
+
# @param params :buy_price_oco [decimal] If ocoorder is true, this field represent the price of the OCO stop order to place
|
14
|
+
# @return [Hash]
|
15
|
+
# @example:
|
16
|
+
# client.new_order("usdbtc", 100, "market", "sell", 0)
|
17
|
+
def new_order(symbol, amount, type, side, price = nil, params = {})
|
18
|
+
check_params(params, %i{is_hidden is_postonly ocoorder buy_price_oco})
|
19
|
+
|
20
|
+
# for 'market' order, we need to pass a random positive price, not nil
|
21
|
+
price ||= 0.001 if type == "market" || type == "exchange market"
|
22
|
+
|
23
|
+
params.merge!({
|
24
|
+
symbol: symbol,
|
25
|
+
amount: amount.to_s,
|
26
|
+
type: type,
|
27
|
+
side: side,
|
28
|
+
exchange: 'gemini',
|
29
|
+
price: "%.10f" % price.to_f.round(10) # Decimalize float price (necessary for small numbers)
|
30
|
+
})
|
31
|
+
authenticated_post("order/new", params: params).body
|
32
|
+
end
|
33
|
+
|
34
|
+
# Submit several new orders at once
|
35
|
+
#
|
36
|
+
# @param orders [Array] Array of Hash with the following elements
|
37
|
+
# @param orders :symbol [string] The name of the symbol
|
38
|
+
# @param orders :amount [decimal] Order size: how much to buy or sell
|
39
|
+
# @param orders :price [decimal] Price to buy or sell at. May omit if a market order
|
40
|
+
# @param orders :exchange [string] "gemini"
|
41
|
+
# @param orders :side [string] Either “buy” or “sell”
|
42
|
+
# @param orders :type [string] Either “market” / “limit” / “stop” / “trailing-stop” / “fill-or-kill”
|
43
|
+
# @return [Hash] with a `object_id` that is an `Array`
|
44
|
+
# @example:
|
45
|
+
# client.multiple_orders([{symbol: "usdbtc", amount: 10, price: 0, exchange: "gemini", side: "buy", type: "market"}])
|
46
|
+
def multiple_orders(orders)
|
47
|
+
authenticated_post("order/new/multi", params: orders).body
|
48
|
+
end
|
49
|
+
|
50
|
+
# Cancel an order
|
51
|
+
#
|
52
|
+
# @param ids [Array] or [integer] or nil
|
53
|
+
# if it's Array it's supposed to specify a list of IDS
|
54
|
+
# if it's an integer it's supposed to be a single ID
|
55
|
+
# if it's not specified it deletes all the orders placed
|
56
|
+
# @return [Hash]
|
57
|
+
# @example
|
58
|
+
# client.cancel_orders([100,231,400])
|
59
|
+
def cancel_orders(ids=nil)
|
60
|
+
case ids
|
61
|
+
when Array
|
62
|
+
authenticated_post("order/cancel/multi", params: {order_ids: ids.map(&:to_i)}).body
|
63
|
+
when Numeric, String
|
64
|
+
authenticated_post("order/cancel", params: {order_id: ids.to_i}).body
|
65
|
+
when NilClass
|
66
|
+
authenticated_post("order/cancel/all").body
|
67
|
+
else
|
68
|
+
raise ParamsError
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Replace an orders with a new one
|
73
|
+
#
|
74
|
+
# @param id [int] the ID of the order to replace
|
75
|
+
# @param symbol [string] the name of the symbol
|
76
|
+
# @param amount [decimal] Order size: how much to buy or sell
|
77
|
+
# @param type [string] Either “market” / “limit” / “stop” / “trailing-stop” / “fill-or-kill” / “exchange market” / “exchange limit” / “exchange stop” / “exchange trailing-stop” / “exchange fill-or-kill”. (type starting by “exchange ” are exchange orders, others are margin trading orders)
|
78
|
+
# @param side [string] Either “buy” or “sell”
|
79
|
+
# @param price [decimal] Price to buy or sell at. May omit if a market order
|
80
|
+
# @param is_hidden [bool] (optional) true if the order should be hidden. Default is false
|
81
|
+
# @param use_remaining [bool] (optional) will use the amount remaining of the canceled order as the amount of the new order. Default is false
|
82
|
+
# @return [Hash] the order
|
83
|
+
# @example:
|
84
|
+
# client.replace_order(100,"usdbtc", 10, "market", "buy", 0)
|
85
|
+
def replace_order(id, symbol, amount, type, side, price, is_hidden=false, use_remaining=false)
|
86
|
+
params = {
|
87
|
+
order_id: id.to_i,
|
88
|
+
symbol: symbol,
|
89
|
+
amount: amount.to_s,
|
90
|
+
type: type,
|
91
|
+
side: side,
|
92
|
+
exchange: 'gemini',
|
93
|
+
is_hidden: is_hidden,
|
94
|
+
use_remaining: use_remaining,
|
95
|
+
price: price.to_s
|
96
|
+
}
|
97
|
+
authenticated_post("order/cancel/replace", params: params).body
|
98
|
+
end
|
99
|
+
|
100
|
+
# Get the status of an order. Is it active? Was it cancelled? To what extent has it been executed? etc.
|
101
|
+
#
|
102
|
+
# @param id
|
103
|
+
# @return [Hash]
|
104
|
+
# @exmaple:
|
105
|
+
# client.order_status(100)
|
106
|
+
def order_status(id)
|
107
|
+
authenticated_post("order/status", params: {order_id: id.to_i}).body
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
# View your active orders.
|
112
|
+
#
|
113
|
+
# @return [Hash]
|
114
|
+
# @example:
|
115
|
+
# client.orders
|
116
|
+
def orders
|
117
|
+
authenticated_post("orders").body
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
end
|