bitmex-api 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/Gemfile.lock +36 -1
- data/README.md +104 -15
- data/TODOs.org +12 -3
- data/bin/chat.rb +11 -0
- data/bin/whales-watching.rb +2 -2
- data/bitmex.gemspec +3 -0
- data/lib/bitmex.rb +16 -1
- data/lib/bitmex/apikey.rb +45 -0
- data/lib/bitmex/base.rb +26 -0
- data/lib/bitmex/chat.rb +57 -0
- data/lib/bitmex/client.rb +186 -61
- data/lib/bitmex/instrument.rb +53 -0
- data/lib/bitmex/order.rb +78 -0
- data/lib/bitmex/position.rb +77 -0
- data/lib/bitmex/quote.rb +32 -0
- data/lib/bitmex/stats.rb +35 -0
- data/lib/bitmex/trade.rb +41 -0
- data/lib/bitmex/user.rb +37 -11
- data/lib/bitmex/version.rb +1 -1
- data/lib/bitmex/websocket.rb +67 -0
- metadata +55 -2
data/lib/bitmex/client.rb
CHANGED
@@ -8,91 +8,176 @@ module Bitmex
|
|
8
8
|
include HTTParty
|
9
9
|
# logger ::Logger.new(STDOUT), :debug, :curl
|
10
10
|
|
11
|
-
ANNOUNCEMENT_ARGS = %w(urgent).freeze
|
12
|
-
APIKEY_ARGS = %w().freeze
|
13
|
-
CHAT_ARGS = %w(channels connected).freeze
|
14
|
-
EXECUTION_ARGS = %w(tradehistory).freeze
|
15
|
-
FUNDING_ARGS = %w().freeze
|
16
|
-
GLOBALNOTIFICATION_ARGS = %w().freeze
|
17
|
-
INSTRUMENT_ARGS = %w(active activeandindices activeintervals compositeindex indices).freeze
|
18
|
-
INSURANCE_ARGS = %w().freeze
|
19
|
-
LEADERBOARD_ARGS = %w().freeze
|
20
|
-
LIQUIDATION_ARGS = %w().freeze
|
21
|
-
ORDER_ARGS = %w().freeze
|
22
|
-
ORDERBOOK_ARGS = %w(L2).freeze
|
23
|
-
POSITION_ARGS = %w().freeze
|
24
|
-
QUOTE_ARGS = %w(bucketed).freeze
|
25
|
-
SCHEMA_ARGS = %w(websockethelp).freeze
|
26
|
-
SETTLEMENT_ARGS = %w().freeze
|
27
|
-
STATS_ARGS = %w(history historyusd).freeze
|
28
|
-
TRADE_ARGS = %w(bucketed).freeze
|
29
|
-
|
30
|
-
TESTNET_HOST = 'testnet.bitmex.com'.freeze
|
31
|
-
MAINNET_HOST = 'www.bitmex.com'.freeze
|
32
|
-
|
33
11
|
AUTHORIZATIONS = %w(apikey execution position globalnotification order leaderboard quote user userevent)
|
34
12
|
|
35
13
|
attr_reader :host, :api_key, :api_secret
|
36
14
|
|
15
|
+
# Create new client instance
|
16
|
+
# @param testnet [Boolean] true for testnet network
|
17
|
+
# @param api_key [String] the api key
|
18
|
+
# @param api_secret [String] the api secret
|
37
19
|
def initialize(testnet: false, api_key: nil, api_secret: nil)
|
38
20
|
@host = testnet ? TESTNET_HOST : MAINNET_HOST
|
39
21
|
@api_key = api_key
|
40
22
|
@api_secret = api_secret
|
41
23
|
end
|
42
24
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
25
|
+
# Get site announcements
|
26
|
+
# @return [Array] the public announcements
|
27
|
+
def announcements
|
28
|
+
get base_path(:announcement) do |response|
|
29
|
+
response_handler response
|
48
30
|
end
|
49
31
|
end
|
50
32
|
|
51
|
-
#
|
52
|
-
#
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
def listen(options, &ablock)
|
57
|
-
EM.run do
|
58
|
-
ws = Faye::WebSocket::Client.new realtime_url
|
33
|
+
# Persistent API Keys for Developers
|
34
|
+
# @return [Bitmex::Apikey] the apikey instance
|
35
|
+
def apikey(api_key = nil)
|
36
|
+
Bitmex::Apikey.new self, api_key
|
37
|
+
end
|
59
38
|
|
60
|
-
|
61
|
-
|
62
|
-
|
39
|
+
# Trollbox Data
|
40
|
+
# @return [Bitmex::Chat] the chat instance
|
41
|
+
def chat
|
42
|
+
Bitmex::Chat.new self
|
43
|
+
end
|
63
44
|
|
64
|
-
|
65
|
-
|
66
|
-
|
45
|
+
# Tradeable Contracts, Indices, and History
|
46
|
+
# @return [Bitmex::Instrument] the instrument model
|
47
|
+
def instrument
|
48
|
+
Bitmex::Instrument.new self
|
49
|
+
end
|
67
50
|
|
68
|
-
|
69
|
-
|
70
|
-
|
51
|
+
# Get funding history
|
52
|
+
# @!macro bitmex.filters
|
53
|
+
# @return [Array] the history
|
54
|
+
def funding(filters = {})
|
55
|
+
get base_path(:funding), params: filters do |response|
|
56
|
+
response_handler response
|
57
|
+
end
|
58
|
+
end
|
71
59
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
60
|
+
# Get insurance fund history
|
61
|
+
# @!macro bitmex.filters
|
62
|
+
# @return [Array] the history
|
63
|
+
def insurance(filters = {})
|
64
|
+
get base_path(:insurance), params: filters do |response|
|
65
|
+
response_handler response
|
66
|
+
end
|
67
|
+
end
|
80
68
|
|
81
|
-
|
82
|
-
|
83
|
-
|
69
|
+
# Get current leaderboard
|
70
|
+
# @param ranking [notional ROE] the ranking type
|
71
|
+
# @return [Array] current leaders
|
72
|
+
def leaderboard(ranking = 'notional')
|
73
|
+
get base_path(:leaderboard), params: { method: ranking } do |response|
|
74
|
+
response_handler response
|
75
|
+
end
|
76
|
+
end
|
84
77
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
78
|
+
# Get liquidation orders
|
79
|
+
# @!macro bitmex.filters
|
80
|
+
# @return [Array] the liquidations
|
81
|
+
def liquidations(filters = {})
|
82
|
+
get base_path(:liquidation), params: filters do |response|
|
83
|
+
response_handler response
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Order Placement, Cancellation, Amending, and History
|
88
|
+
# @return [Bitmex::Order] the order model
|
89
|
+
def orders
|
90
|
+
# TODO: use class method
|
91
|
+
Bitmex::Order.new(self)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Get an order by id
|
95
|
+
# @param orderID [String] the order #
|
96
|
+
# @param clOrdID [String] the client order #
|
97
|
+
# @return [Bitmex::Order] the order model
|
98
|
+
def order(orderID: nil, clOrdID: nil)
|
99
|
+
raise ArgumentError, 'either orderID or clOrdID is required' if orderID.nil? && clOrdID.nil?
|
100
|
+
|
101
|
+
Bitmex::Order.new(self, orderID, clOrdID)
|
102
|
+
end
|
103
|
+
|
104
|
+
# Get current orderbook in vertical format
|
105
|
+
# @param symbol [String] instrument symbol, send a series (e.g. XBT) to get data for the nearest contract in that series
|
106
|
+
# @param depth [Integer] orderbook depth per side. send 0 for full depth.
|
107
|
+
# @return [Array] the orderbook
|
108
|
+
def orderbook(symbol, depth: 25)
|
109
|
+
params = { symbol: symbol, depth: depth }
|
110
|
+
get base_path('orderbook/L2'), params: params do |response|
|
111
|
+
response_handler response
|
89
112
|
end
|
90
113
|
end
|
91
114
|
|
115
|
+
# Summary of Open and Closed Positions
|
116
|
+
# @return [Array] the list of positions
|
117
|
+
def positions
|
118
|
+
# TODO: use class method
|
119
|
+
Bitmex::Position.new(self).all
|
120
|
+
end
|
121
|
+
|
122
|
+
# Get an open position
|
123
|
+
# @param symbol [String] symbol of position
|
124
|
+
# @return [Bitmex::Position] open position
|
125
|
+
def position(symbol)
|
126
|
+
Bitmex::Position.new(self, symbol)
|
127
|
+
end
|
128
|
+
|
129
|
+
# Best Bid/Offer Snapshots & Historical Bins
|
130
|
+
# @return [Bitmex::Quote] the quote model
|
131
|
+
def quotes
|
132
|
+
# TODO: use class method
|
133
|
+
Bitmex::Quote.new self
|
134
|
+
end
|
135
|
+
|
136
|
+
# Get model schemata for data objects returned by this AP
|
137
|
+
# @return [Hash] the schema
|
138
|
+
def schema
|
139
|
+
get base_path(:schema) do |response|
|
140
|
+
response_handler response
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# Get settlement history
|
145
|
+
# @return [Array] the settlement history
|
146
|
+
def settlement
|
147
|
+
get base_path(:settlement) do |response|
|
148
|
+
response_handler response
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Exchange statistics
|
153
|
+
# @return [Bitmex::Stats] the stats model
|
154
|
+
def stats
|
155
|
+
Bitmex::Stats.new self
|
156
|
+
end
|
157
|
+
|
158
|
+
# Individual and bucketed trades
|
159
|
+
# @return [Bitmex::Trade] the trade model
|
160
|
+
def trades
|
161
|
+
Bitmex::Trade.new self
|
162
|
+
end
|
163
|
+
|
164
|
+
# Account operations
|
165
|
+
# @return [Bitmex::User] the user model
|
92
166
|
def user
|
93
167
|
Bitmex::User.new self
|
94
168
|
end
|
95
169
|
|
170
|
+
# Listen to generic topics
|
171
|
+
# @param topics [Hash] topics to listen to e.g. { trade: "XBTUSD" }
|
172
|
+
# @yield [data] data pushed via websocket
|
173
|
+
def listen(topics, &ablock)
|
174
|
+
EM.run do
|
175
|
+
topics.each do |topic, symbol|
|
176
|
+
websocket.subscribe topic, symbol, &ablock
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
96
181
|
#
|
97
182
|
# Stop websocket listener
|
98
183
|
#
|
@@ -100,7 +185,12 @@ module Bitmex
|
|
100
185
|
EM.stop_event_loop
|
101
186
|
end
|
102
187
|
|
103
|
-
def
|
188
|
+
def websocket
|
189
|
+
@websocket ||= Websocket.new realtime_url
|
190
|
+
end
|
191
|
+
|
192
|
+
# TODO: move these methods into rest client
|
193
|
+
def get(path, params: {}, auth: false, &ablock)
|
104
194
|
options = {}
|
105
195
|
options[:query] = params unless params.empty?
|
106
196
|
options[:headers] = headers 'GET', path, '' if auth
|
@@ -117,10 +207,45 @@ module Bitmex
|
|
117
207
|
options[:headers] = headers 'PUT', path, body, json: json if auth
|
118
208
|
|
119
209
|
response = self.class.put "#{domain_url}#{path}", options
|
120
|
-
puts response.body
|
121
210
|
yield response
|
122
211
|
end
|
123
212
|
|
213
|
+
def post(path, params: {}, auth: true, json: true)
|
214
|
+
body = json ? params.to_json.to_s : URI.encode_www_form(params)
|
215
|
+
|
216
|
+
options = {}
|
217
|
+
options[:body] = body
|
218
|
+
options[:headers] = headers 'POST', path, body, json: json if auth
|
219
|
+
|
220
|
+
response = self.class.post "#{domain_url}#{path}", options
|
221
|
+
yield response
|
222
|
+
end
|
223
|
+
|
224
|
+
def delete(path, params: {}, auth: true, json: true)
|
225
|
+
body = json ? params.to_json.to_s : URI.encode_www_form(params)
|
226
|
+
|
227
|
+
options = {}
|
228
|
+
options[:body] = body
|
229
|
+
options[:headers] = headers 'DELETE', path, body, json: json if auth
|
230
|
+
|
231
|
+
response = self.class.delete "#{domain_url}#{path}", options
|
232
|
+
yield response
|
233
|
+
end
|
234
|
+
|
235
|
+
def base_path(resource, action = '')
|
236
|
+
"/api/v1/#{resource}/#{action}"
|
237
|
+
end
|
238
|
+
|
239
|
+
def response_handler(response)
|
240
|
+
fail response.body unless response.success?
|
241
|
+
|
242
|
+
if response.parsed_response.is_a? Array
|
243
|
+
response.to_a.map { |s| Bitmex::Mash.new s }
|
244
|
+
else
|
245
|
+
Bitmex::Mash.new response
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
124
249
|
private
|
125
250
|
|
126
251
|
def method_missing(m, *args, &ablock)
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Bitmex
|
2
|
+
# Tradeable Contracts, Indices, and History
|
3
|
+
# @author Iulian Costan
|
4
|
+
class Instrument < Base
|
5
|
+
# Get all instruments
|
6
|
+
# @!macro bitmex.filters
|
7
|
+
# @return [Array] all instruments
|
8
|
+
def all(filters = {})
|
9
|
+
client.get instrument_path, params: filters do |response|
|
10
|
+
response_handler response
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Get all active instruments and instruments that have expired in <24hrs.
|
15
|
+
# @return [Array] active instruments
|
16
|
+
def active
|
17
|
+
client.get instrument_path('active') do |response|
|
18
|
+
response_handler response
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Return all active contract series and interval pairs
|
23
|
+
# @return [Bitmex::Mash] active intervals and symbols
|
24
|
+
def intervals
|
25
|
+
client.get instrument_path('activeIntervals') do |response|
|
26
|
+
response_handler response
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Show constituent parts of an index.
|
31
|
+
# @!macro bitmex.filters
|
32
|
+
# @return [Array] the parts of an index
|
33
|
+
def composite_index(filters = { symbol: '.XBT' })
|
34
|
+
client.get instrument_path('compositeIndex'), params: filters do |response|
|
35
|
+
response_handler response
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Get all price indices
|
40
|
+
# @return [Array] all indices
|
41
|
+
def indices
|
42
|
+
client.get instrument_path('indices') do |response|
|
43
|
+
response_handler response
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def instrument_path(action = '')
|
50
|
+
base_path :instrument, action
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/bitmex/order.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
module Bitmex
|
2
|
+
# Order Placement, Cancellation, Amending, and History
|
3
|
+
# @author Iulian Costan
|
4
|
+
class Order < Base
|
5
|
+
attr_reader :orderID, :clOrdID
|
6
|
+
|
7
|
+
def initialize(client, orderID = nil, clOrdID = nil)
|
8
|
+
super client
|
9
|
+
@orderID = orderID
|
10
|
+
@clOrdID = clOrdID
|
11
|
+
end
|
12
|
+
|
13
|
+
# Get your orders
|
14
|
+
# @!macro bitmex.filters
|
15
|
+
# @return [Array] the orders
|
16
|
+
def all(filters = {})
|
17
|
+
client.get order_path, params: filters, auth: true do |response|
|
18
|
+
response_handler response
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Amend the quantity or price of an open order
|
23
|
+
# @param attributes [Hash] the fields to update
|
24
|
+
# @option attributes [Integer] :orderQty Optional order quantity in units of the instrument (i.e. contracts)
|
25
|
+
# @option attributes [Integer] :leavesQty Optional leaves quantity in units of the instrument (i.e. contracts). Useful for amending partially filled orders.
|
26
|
+
# @option attributes [Double] :price Optional limit price for 'Limit', 'StopLimit', and 'LimitIfTouched' orders.
|
27
|
+
# @option attributes [Double] :stopPx Optional trigger price for 'Stop', 'StopLimit', 'MarketIfTouched', and 'LimitIfTouched' orders. Use a price below the current price for stop-sell orders and buy-if-touched orders.
|
28
|
+
# @option attributes [Double] :pegOffsetValue Optional trailing offset from the current price for 'Stop', 'StopLimit', 'MarketIfTouched', and 'LimitIfTouched' orders; use a negative offset for stop-sell orders and buy-if-touched orders. Optional offset from the peg price for 'Pegged' orders.
|
29
|
+
# @option attributes [String] :text Optional amend annotation. e.g. 'Adjust skew'
|
30
|
+
# @return [Bitmex::Mash] the updated order
|
31
|
+
def update(attributes)
|
32
|
+
params = attributes.merge orderID: orderID, origClOrdID: clOrdID
|
33
|
+
client.put order_path, params: params do |response|
|
34
|
+
response_handler response
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Place new order
|
39
|
+
# @param symbol [String] instrument symbol
|
40
|
+
# @param attributes [Hash] order attributes
|
41
|
+
# @option attributes [Buy, Sell] :side Order side. Defaults to 'Buy' unless orderQty is negative
|
42
|
+
# @option attributes [Integer] :orderQty Order quantity in units of the instrument (i.e. contracts)
|
43
|
+
# @option attributes [Double] :price Optional limit price for 'Limit', 'StopLimit', and 'LimitIfTouched' orders
|
44
|
+
# @option attributes [Double] :displayQty Optional quantity to display in the book. Use 0 for a fully hidden order.
|
45
|
+
# @option attributes [Double] :stopPx Optional trigger price for 'Stop', 'StopLimit', 'MarketIfTouched', and 'LimitIfTouched' orders. Use a price below the current price for stop-sell orders and buy-if-touched orders. Use execInst of 'MarkPrice' or 'LastPrice' to define the current price used for triggering.
|
46
|
+
# @option attributes [String] :clOrdID Optional Client Order ID. This clOrdID will come back on the order and any related executions.
|
47
|
+
# @option attributes [Double] :pegOffsetValue Optional trailing offset from the current price for 'Stop', 'StopLimit', 'MarketIfTouched', and 'LimitIfTouched' orders; use a negative offset for stop-sell orders and buy-if-touched orders. Optional offset from the peg price for 'Pegged' orders.
|
48
|
+
# @option attributes [LastPeg, MidPricePeg, MarketPeg, PrimaryPeg, TrailingStopPeg] :pegPriceType Optional peg price type.
|
49
|
+
# @option attributes [Market, Limit, Stop, StopLimit, MarketIfTouched, LimitIfTouched, MarketWithLeftOverAsLimit, Pegged] :ordType Order type. Defaults to 'Limit' when price is specified. Defaults to 'Stop' when stopPx is specified. Defaults to 'StopLimit' when price and stopPx are specified.
|
50
|
+
# @option attributes [Day, GoodTillCancel, ImmediateOrCancel, FillOrKill] :timeInForce Time in force. Defaults to 'GoodTillCancel' for 'Limit', 'StopLimit', 'LimitIfTouched', and 'MarketWithLeftOverAsLimit' orders.
|
51
|
+
# @option attributes [ParticipateDoNotInitiate, AllOrNone, MarkPrice, IndexPrice, LastPrice, Close, ReduceOnly, Fixed] :execInst Optional execution instructions. AllOrNone' instruction requires displayQty to be 0. 'MarkPrice', 'IndexPrice' or 'LastPrice' instruction valid for 'Stop', 'StopLimit', 'MarketIfTouched', and 'LimitIfTouched' orders.
|
52
|
+
# @option attributes [String] :text Optional amend annotation. e.g. 'Take profit'
|
53
|
+
# @return [Bitmex::Mash] the created order
|
54
|
+
def create(symbol, attributes)
|
55
|
+
params = attributes.merge symbol: symbol
|
56
|
+
client.post order_path, params: params do |response|
|
57
|
+
response_handler response
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Cancel an order
|
62
|
+
# @param text [String] Optional cancellation annotation. e.g. 'Spread Exceeded'.
|
63
|
+
# @return [Bitmex::Mash] the canceled order
|
64
|
+
def cancel(text = nil)
|
65
|
+
params = { orderID: orderID, clOrdID: clOrdID, text: text }
|
66
|
+
client.delete order_path, params: params do |response|
|
67
|
+
# a single order only
|
68
|
+
response_handler(response).first
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def order_path(action = '')
|
75
|
+
client.base_path 'order', action
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Bitmex
|
2
|
+
# Summary of Open and Closed Positions
|
3
|
+
# @author Iulian Costan
|
4
|
+
class Position < Base
|
5
|
+
attr_reader :symbol
|
6
|
+
|
7
|
+
# A new instance of Position
|
8
|
+
# @param client [Bitmex::Client] the HTTP client
|
9
|
+
# @param symbol [String] the symbol of the underlying position
|
10
|
+
def initialize(client, symbol = 'XBTUSD')
|
11
|
+
super client
|
12
|
+
@symbol = symbol
|
13
|
+
end
|
14
|
+
|
15
|
+
# Get your positions
|
16
|
+
# @return [Array] the list of positions
|
17
|
+
def all
|
18
|
+
client.get position_path, auth: true do |response|
|
19
|
+
response_handler response
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Enable isolated margin or cross margin per-position
|
24
|
+
# @param enabled [true, false] true for isolated margin, false cross margin
|
25
|
+
# @return [Hash] the updated position
|
26
|
+
def isolate(enabled: true)
|
27
|
+
path = position_path(:isolate)
|
28
|
+
params = { symbol: symbol, enabled: enabled }
|
29
|
+
client.post path, params: params do |response|
|
30
|
+
response_handler response
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Choose leverage for a position
|
35
|
+
# @param leverage [0-100] leverage value. send a number between 0.01 and 100 to enable isolated margin with a fixed leverage. send 0 to enable cross margin
|
36
|
+
# @return [Hash] the updated position
|
37
|
+
def leverage(leverage)
|
38
|
+
raise ArgumentError, "leverage #{leverage} is outside of [0..100] range" unless (0..100).include? leverage
|
39
|
+
|
40
|
+
path = position_path(:leverage)
|
41
|
+
params = { symbol: symbol, leverage: leverage }
|
42
|
+
client.post path, params: params do |response|
|
43
|
+
response_handler response
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Update your risk limit
|
48
|
+
# @param risk_limit [Double] new risk limit, in Satoshis.
|
49
|
+
# @return [Hash] the updated position
|
50
|
+
def risk_limit(risk_limit)
|
51
|
+
path = position_path(:riskLimit)
|
52
|
+
params = { symbol: symbol, riskLimit: risk_limit }
|
53
|
+
client.post path, params: params do |response|
|
54
|
+
response_handler response
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Transfer equity in or out of a position
|
59
|
+
# @example Transfer 1000 Satoshi
|
60
|
+
# position = client.position('XBTUSD').transfer_margin 1000
|
61
|
+
# @param amount [Double] amount to transfer, in Satoshis. may be negative.
|
62
|
+
# @return [Hash] the updated position
|
63
|
+
def transfer_margin(amount)
|
64
|
+
path = position_path(:transferMargin)
|
65
|
+
params = { symbol: symbol, amount: amount }
|
66
|
+
client.post path, params: params do |response|
|
67
|
+
response_handler response
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def position_path(action = '')
|
74
|
+
client.base_path :position, action
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|