gemini-rb 0.0.1
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.
- 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
|