mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-14 23:16:49 +00:00
* bitmex: normalize account info currencies Bitmex has an interesting way of returning BTC balances, it returns them as XBt and denominated in Satoshis instead. Normalize that still in the bitmex wrapper by performing the conversion and returning the normal use BTC currency. * Change NW contract to NQ Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>
973 lines
32 KiB
Go
973 lines
32 KiB
Go
package bitmex
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/thrasher-corp/gocryptotrader/common/crypto"
|
|
"github.com/thrasher-corp/gocryptotrader/currency"
|
|
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
|
|
)
|
|
|
|
// Bitmex is the overarching type across this package
|
|
type Bitmex struct {
|
|
exchange.Base
|
|
}
|
|
|
|
const (
|
|
bitmexAPIVersion = "v1"
|
|
bitmexAPIURL = "https://www.bitmex.com/api/v1"
|
|
bitmexAPItestnetURL = "https://testnet.bitmex.com/api/v1"
|
|
|
|
// Public endpoints
|
|
bitmexEndpointAnnouncement = "/announcement"
|
|
bitmexEndpointAnnouncementUrgent = "/announcement/urgent"
|
|
bitmexEndpointOrderbookL2 = "/orderBook/L2"
|
|
bitmexEndpointTrollbox = "/chat"
|
|
bitmexEndpointTrollboxChannels = "/chat/channels"
|
|
bitmexEndpointTrollboxConnected = "/chat/connected"
|
|
bitmexEndpointFundingHistory = "/funding?"
|
|
bitmexEndpointInstruments = "/instrument"
|
|
bitmexEndpointActiveInstruments = "/instrument/active"
|
|
bitmexEndpointActiveAndIndexInstruments = "/instrument/activeAndIndices"
|
|
bitmexEndpointActiveIntervals = "/instrument/activeIntervals"
|
|
bitmexEndpointCompositeIndex = "/instrument/compositeIndex"
|
|
bitmexEndpointIndices = "/instrument/indices"
|
|
bitmexEndpointInsuranceHistory = "/insurance"
|
|
bitmexEndpointLiquidation = "/liquidation"
|
|
bitmexEndpointLeader = "/leaderboard"
|
|
bitmexEndpointAlias = "/leaderboard/name"
|
|
bitmexEndpointQuote = "/quote"
|
|
bitmexEndpointQuoteBucketed = "/quote/bucketed"
|
|
bitmexEndpointSettlement = "/settlement"
|
|
bitmexEndpointStats = "/stats"
|
|
bitmexEndpointStatsHistory = "/stats/history"
|
|
bitmexEndpointStatsSummary = "/stats/historyUSD"
|
|
bitmexEndpointTrade = "/trade"
|
|
bitmexEndpointTradeBucketed = "/trade/bucketed"
|
|
bitmexEndpointUserCheckReferralCode = "/user/checkReferralCode"
|
|
bitmexEndpointUserMinWithdrawalFee = "/user/minWithdrawalFee"
|
|
|
|
// Authenticated endpoints
|
|
bitmexEndpointAPIkeys = "/apiKey"
|
|
bitmexEndpointDisableAPIkey = "/apiKey/disable"
|
|
bitmexEndpointEnableAPIkey = "/apiKey/enable"
|
|
bitmexEndpointTrollboxSend = "/chat"
|
|
bitmexEndpointExecution = "/execution"
|
|
bitmexEndpointExecutionTradeHistory = "/execution/tradeHistory"
|
|
bitmexEndpointNotifications = "/notification"
|
|
bitmexEndpointOrder = "/order"
|
|
bitmexEndpointCancelAllOrders = "/order/all"
|
|
bitmexEndpointBulk = "/order/bulk"
|
|
bitmexEndpointCancelOrderAfter = "/order/cancelAllAfter"
|
|
bitmexEndpointClosePosition = "/order/closePosition"
|
|
bitmexEndpointPosition = "/position"
|
|
bitmexEndpointIsolatePosition = "/position/isolate"
|
|
bitmexEndpointLeveragePosition = "/position/leverage"
|
|
bitmexEndpointAdjustRiskLimit = "/position/riskLimit"
|
|
bitmexEndpointTransferMargin = "/position/transferMargin"
|
|
bitmexEndpointUser = "/user"
|
|
bitmexEndpointUserAffiliate = "/user/affiliateStatus"
|
|
bitmexEndpointUserCancelWithdraw = "/user/cancelWithdrawal"
|
|
bitmexEndpointUserCommision = "/user/commission"
|
|
bitmexEndpointUserConfirmEmail = "/user/confirmEmail"
|
|
bitmexEndpointUserConfirmTFA = "/user/confirmEnableTFA"
|
|
bitmexEndpointUserConfirmWithdrawal = "/user/confirmWithdrawal"
|
|
bitmexEndpointUserDepositAddress = "/user/depositAddress"
|
|
bitmexEndpointUserDisableTFA = "/user/disableTFA"
|
|
bitmexEndpointUserLogout = "/user/logout"
|
|
bitmexEndpointUserLogoutAll = "/user/logoutAll"
|
|
bitmexEndpointUserMargin = "/user/margin"
|
|
bitmexEndpointUserPreferences = "/user/preferences"
|
|
bitmexEndpointUserRequestTFA = "/user/requestEnableTFA"
|
|
bitmexEndpointUserWallet = "/user/wallet"
|
|
bitmexEndpointUserWalletHistory = "/user/walletHistory"
|
|
bitmexEndpointUserWalletSummary = "/user/walletSummary"
|
|
bitmexEndpointUserRequestWithdraw = "/user/requestWithdrawal"
|
|
|
|
constSatoshiBTC = 1e-08
|
|
|
|
// ContractPerpetual perpetual contract type
|
|
ContractPerpetual = iota
|
|
// ContractFutures futures contract type
|
|
ContractFutures
|
|
// ContractDownsideProfit downside profit contract type
|
|
ContractDownsideProfit
|
|
// ContractUpsideProfit upside profit contract type
|
|
ContractUpsideProfit
|
|
)
|
|
|
|
// GetAnnouncement returns the general announcements from Bitmex
|
|
func (b *Bitmex) GetAnnouncement(ctx context.Context) ([]Announcement, error) {
|
|
var announcement []Announcement
|
|
|
|
return announcement, b.SendHTTPRequest(ctx, exchange.RestSpot, bitmexEndpointAnnouncement,
|
|
nil,
|
|
&announcement)
|
|
}
|
|
|
|
// GetUrgentAnnouncement returns an urgent announcement for your account
|
|
func (b *Bitmex) GetUrgentAnnouncement(ctx context.Context) ([]Announcement, error) {
|
|
var announcement []Announcement
|
|
|
|
return announcement, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodGet,
|
|
bitmexEndpointAnnouncementUrgent,
|
|
nil,
|
|
&announcement)
|
|
}
|
|
|
|
// GetAPIKeys returns the APIkeys from bitmex
|
|
func (b *Bitmex) GetAPIKeys(ctx context.Context) ([]APIKey, error) {
|
|
var keys []APIKey
|
|
|
|
return keys, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodGet,
|
|
bitmexEndpointAPIkeys,
|
|
nil,
|
|
&keys)
|
|
}
|
|
|
|
// RemoveAPIKey removes an Apikey from the bitmex trading engine
|
|
func (b *Bitmex) RemoveAPIKey(ctx context.Context, params APIKeyParams) (bool, error) {
|
|
var keyDeleted bool
|
|
|
|
return keyDeleted, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodDelete,
|
|
bitmexEndpointAPIkeys,
|
|
¶ms,
|
|
&keyDeleted)
|
|
}
|
|
|
|
// DisableAPIKey disables an Apikey from the bitmex trading engine
|
|
func (b *Bitmex) DisableAPIKey(ctx context.Context, params APIKeyParams) (APIKey, error) {
|
|
var keyInfo APIKey
|
|
|
|
return keyInfo, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost,
|
|
bitmexEndpointDisableAPIkey,
|
|
¶ms,
|
|
&keyInfo)
|
|
}
|
|
|
|
// EnableAPIKey enables an Apikey from the bitmex trading engine
|
|
func (b *Bitmex) EnableAPIKey(ctx context.Context, params APIKeyParams) (APIKey, error) {
|
|
var keyInfo APIKey
|
|
|
|
return keyInfo, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost,
|
|
bitmexEndpointEnableAPIkey,
|
|
¶ms,
|
|
&keyInfo)
|
|
}
|
|
|
|
// GetTrollboxMessages returns messages from the bitmex trollbox
|
|
func (b *Bitmex) GetTrollboxMessages(ctx context.Context, params ChatGetParams) ([]Chat, error) {
|
|
var messages []Chat
|
|
|
|
return messages, b.SendHTTPRequest(ctx, exchange.RestSpot, bitmexEndpointTrollbox, ¶ms, &messages)
|
|
}
|
|
|
|
// SendTrollboxMessage sends a message to the bitmex trollbox
|
|
func (b *Bitmex) SendTrollboxMessage(ctx context.Context, params ChatSendParams) ([]Chat, error) {
|
|
var messages []Chat
|
|
|
|
return messages, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost,
|
|
bitmexEndpointTrollboxSend,
|
|
¶ms,
|
|
&messages)
|
|
}
|
|
|
|
// GetTrollboxChannels the channels from the the bitmex trollbox
|
|
func (b *Bitmex) GetTrollboxChannels(ctx context.Context) ([]ChatChannel, error) {
|
|
var channels []ChatChannel
|
|
|
|
return channels, b.SendHTTPRequest(ctx, exchange.RestSpot, bitmexEndpointTrollboxChannels,
|
|
nil,
|
|
&channels)
|
|
}
|
|
|
|
// GetTrollboxConnectedUsers the channels from the the bitmex trollbox
|
|
func (b *Bitmex) GetTrollboxConnectedUsers(ctx context.Context) (ConnectedUsers, error) {
|
|
var users ConnectedUsers
|
|
|
|
return users, b.SendHTTPRequest(ctx, exchange.RestSpot, bitmexEndpointTrollboxConnected, nil, &users)
|
|
}
|
|
|
|
// GetAccountExecutions returns all raw transactions, which includes order
|
|
// opening and cancelation, and order status changes. It can be quite noisy.
|
|
// More focused information is available at /execution/tradeHistory.
|
|
func (b *Bitmex) GetAccountExecutions(ctx context.Context, params *GenericRequestParams) ([]Execution, error) {
|
|
var executionList []Execution
|
|
|
|
return executionList, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodGet,
|
|
bitmexEndpointExecution,
|
|
params,
|
|
&executionList)
|
|
}
|
|
|
|
// GetAccountExecutionTradeHistory returns all balance-affecting executions.
|
|
// This includes each trade, insurance charge, and settlement.
|
|
func (b *Bitmex) GetAccountExecutionTradeHistory(ctx context.Context, params *GenericRequestParams) ([]Execution, error) {
|
|
var tradeHistory []Execution
|
|
|
|
return tradeHistory, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodGet,
|
|
bitmexEndpointExecutionTradeHistory,
|
|
params,
|
|
&tradeHistory)
|
|
}
|
|
|
|
// GetFullFundingHistory returns funding history
|
|
func (b *Bitmex) GetFullFundingHistory(ctx context.Context, symbol, count, filter, columns, start string, reverse bool, startTime, endTime time.Time) ([]Funding, error) {
|
|
var fundingHistory []Funding
|
|
params := url.Values{}
|
|
params.Set("symbol", symbol)
|
|
params.Set("count", count)
|
|
params.Set("filter", filter)
|
|
params.Set("columns", columns)
|
|
params.Set("start", start)
|
|
params.Set("reverse", "true")
|
|
if !reverse {
|
|
params.Set("reverse", "false")
|
|
}
|
|
if !startTime.IsZero() && !endTime.IsZero() {
|
|
if startTime.After(endTime) {
|
|
return nil, errors.New("startTime cannot be after endTime")
|
|
}
|
|
params.Set("startTime", startTime.Format(time.RFC3339))
|
|
params.Set("endTime", endTime.Format(time.RFC3339))
|
|
}
|
|
return fundingHistory, b.SendHTTPRequest(ctx, exchange.RestSpot, bitmexEndpointFundingHistory+params.Encode(),
|
|
nil,
|
|
&fundingHistory)
|
|
}
|
|
|
|
// GetInstruments returns instrument data
|
|
func (b *Bitmex) GetInstruments(ctx context.Context, params *GenericRequestParams) ([]Instrument, error) {
|
|
var instruments []Instrument
|
|
|
|
return instruments, b.SendHTTPRequest(ctx, exchange.RestSpot, bitmexEndpointInstruments,
|
|
params,
|
|
&instruments)
|
|
}
|
|
|
|
// GetActiveInstruments returns active instruments
|
|
func (b *Bitmex) GetActiveInstruments(ctx context.Context, params *GenericRequestParams) ([]Instrument, error) {
|
|
var activeInstruments []Instrument
|
|
|
|
return activeInstruments, b.SendHTTPRequest(ctx, exchange.RestSpot, bitmexEndpointActiveInstruments,
|
|
params,
|
|
&activeInstruments)
|
|
}
|
|
|
|
// GetActiveAndIndexInstruments returns all active instruments and all indices
|
|
func (b *Bitmex) GetActiveAndIndexInstruments(ctx context.Context) ([]Instrument, error) {
|
|
var activeAndIndices []Instrument
|
|
|
|
return activeAndIndices,
|
|
b.SendHTTPRequest(ctx, exchange.RestSpot, bitmexEndpointActiveAndIndexInstruments,
|
|
nil,
|
|
&activeAndIndices)
|
|
}
|
|
|
|
// GetActiveIntervals returns funding history
|
|
func (b *Bitmex) GetActiveIntervals(ctx context.Context) (InstrumentInterval, error) {
|
|
var interval InstrumentInterval
|
|
|
|
return interval, b.SendHTTPRequest(ctx, exchange.RestSpot, bitmexEndpointActiveIntervals,
|
|
nil,
|
|
&interval)
|
|
}
|
|
|
|
// GetCompositeIndex returns composite index
|
|
func (b *Bitmex) GetCompositeIndex(ctx context.Context, symbol, count, filter, columns, start, reverse string, startTime, endTime time.Time) ([]IndexComposite, error) {
|
|
var compositeIndices []IndexComposite
|
|
params := url.Values{}
|
|
params.Set("symbol", symbol)
|
|
if count != "" {
|
|
params.Set("count", count)
|
|
}
|
|
if filter != "" {
|
|
params.Set("filter", filter)
|
|
}
|
|
if columns != "" {
|
|
params.Set("columns", columns)
|
|
}
|
|
if start != "" {
|
|
params.Set("start", start)
|
|
}
|
|
if reverse != "" {
|
|
params.Set("reverse", "true")
|
|
}
|
|
if !startTime.IsZero() && !endTime.IsZero() {
|
|
if startTime.After(endTime) {
|
|
return nil, errors.New("startTime cannot be after endTime")
|
|
}
|
|
params.Set("startTime", startTime.Format(time.RFC3339))
|
|
params.Set("endTime", endTime.Format(time.RFC3339))
|
|
}
|
|
return compositeIndices, b.SendHTTPRequest(ctx, exchange.RestSpot, bitmexEndpointCompositeIndex+"?"+params.Encode(),
|
|
nil,
|
|
&compositeIndices)
|
|
}
|
|
|
|
// GetIndices returns all price indices
|
|
func (b *Bitmex) GetIndices(ctx context.Context) ([]Instrument, error) {
|
|
var indices []Instrument
|
|
|
|
return indices, b.SendHTTPRequest(ctx, exchange.RestSpot, bitmexEndpointIndices, nil, &indices)
|
|
}
|
|
|
|
// GetInsuranceFundHistory returns insurance fund history
|
|
func (b *Bitmex) GetInsuranceFundHistory(ctx context.Context, params *GenericRequestParams) ([]Insurance, error) {
|
|
var history []Insurance
|
|
|
|
return history, b.SendHTTPRequest(ctx, exchange.RestSpot, bitmexEndpointIndices, params, &history)
|
|
}
|
|
|
|
// GetLeaderboard returns leaderboard information
|
|
func (b *Bitmex) GetLeaderboard(ctx context.Context, params LeaderboardGetParams) ([]Leaderboard, error) {
|
|
var leader []Leaderboard
|
|
|
|
return leader, b.SendHTTPRequest(ctx, exchange.RestSpot, bitmexEndpointLeader, params, &leader)
|
|
}
|
|
|
|
// GetAliasOnLeaderboard returns your alias on the leaderboard
|
|
func (b *Bitmex) GetAliasOnLeaderboard(ctx context.Context) (Alias, error) {
|
|
var alias Alias
|
|
|
|
return alias, b.SendHTTPRequest(ctx, exchange.RestSpot, bitmexEndpointAlias, nil, &alias)
|
|
}
|
|
|
|
// GetLiquidationOrders returns liquidation orders
|
|
func (b *Bitmex) GetLiquidationOrders(ctx context.Context, params *GenericRequestParams) ([]Liquidation, error) {
|
|
var orders []Liquidation
|
|
|
|
return orders, b.SendHTTPRequest(ctx, exchange.RestSpot, bitmexEndpointLiquidation,
|
|
params,
|
|
&orders)
|
|
}
|
|
|
|
// GetCurrentNotifications returns your current notifications
|
|
func (b *Bitmex) GetCurrentNotifications(ctx context.Context) ([]Notification, error) {
|
|
var notifications []Notification
|
|
|
|
return notifications, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodGet,
|
|
bitmexEndpointNotifications,
|
|
nil,
|
|
¬ifications)
|
|
}
|
|
|
|
// GetOrders returns all the orders, open and closed
|
|
func (b *Bitmex) GetOrders(ctx context.Context, params *OrdersRequest) ([]Order, error) {
|
|
var orders []Order
|
|
return orders, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodGet,
|
|
bitmexEndpointOrder,
|
|
params,
|
|
&orders)
|
|
}
|
|
|
|
// AmendOrder amends the quantity or price of an open order
|
|
func (b *Bitmex) AmendOrder(ctx context.Context, params *OrderAmendParams) (Order, error) {
|
|
var order Order
|
|
|
|
return order, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPut,
|
|
bitmexEndpointOrder,
|
|
params,
|
|
&order)
|
|
}
|
|
|
|
// CreateOrder creates a new order
|
|
func (b *Bitmex) CreateOrder(ctx context.Context, params *OrderNewParams) (Order, error) {
|
|
var orderInfo Order
|
|
|
|
return orderInfo, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost,
|
|
bitmexEndpointOrder,
|
|
params,
|
|
&orderInfo)
|
|
}
|
|
|
|
// CancelOrders cancels one or a batch of orders on the exchange and returns
|
|
// a cancelled order list
|
|
func (b *Bitmex) CancelOrders(ctx context.Context, params *OrderCancelParams) ([]Order, error) {
|
|
var cancelledOrders []Order
|
|
|
|
return cancelledOrders, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodDelete,
|
|
bitmexEndpointOrder,
|
|
params,
|
|
&cancelledOrders)
|
|
}
|
|
|
|
// CancelAllExistingOrders cancels all open orders on the exchange
|
|
func (b *Bitmex) CancelAllExistingOrders(ctx context.Context, params OrderCancelAllParams) ([]Order, error) {
|
|
var cancelledOrders []Order
|
|
|
|
return cancelledOrders, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodDelete,
|
|
bitmexEndpointCancelAllOrders,
|
|
params,
|
|
&cancelledOrders)
|
|
}
|
|
|
|
// AmendBulkOrders amends multiple orders for the same symbol
|
|
func (b *Bitmex) AmendBulkOrders(ctx context.Context, params OrderAmendBulkParams) ([]Order, error) {
|
|
var amendedOrders []Order
|
|
|
|
return amendedOrders, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPut,
|
|
bitmexEndpointBulk,
|
|
params,
|
|
&amendedOrders)
|
|
}
|
|
|
|
// CreateBulkOrders creates multiple orders for the same symbol
|
|
func (b *Bitmex) CreateBulkOrders(ctx context.Context, params OrderNewBulkParams) ([]Order, error) {
|
|
var orders []Order
|
|
|
|
return orders, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost,
|
|
bitmexEndpointBulk,
|
|
params,
|
|
&orders)
|
|
}
|
|
|
|
// CancelAllOrdersAfterTime closes all positions after a certain time period
|
|
func (b *Bitmex) CancelAllOrdersAfterTime(ctx context.Context, params OrderCancelAllAfterParams) ([]Order, error) {
|
|
var cancelledOrder []Order
|
|
|
|
return cancelledOrder, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost,
|
|
bitmexEndpointCancelOrderAfter,
|
|
params,
|
|
&cancelledOrder)
|
|
}
|
|
|
|
// ClosePosition closes a position WARNING deprecated use /order endpoint
|
|
func (b *Bitmex) ClosePosition(ctx context.Context, params OrderClosePositionParams) ([]Order, error) {
|
|
var closedPositions []Order
|
|
|
|
return closedPositions, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost,
|
|
bitmexEndpointOrder,
|
|
params,
|
|
&closedPositions)
|
|
}
|
|
|
|
// GetOrderbook returns layer two orderbook data
|
|
func (b *Bitmex) GetOrderbook(ctx context.Context, params OrderBookGetL2Params) ([]OrderBookL2, error) {
|
|
var orderBooks []OrderBookL2
|
|
|
|
return orderBooks, b.SendHTTPRequest(ctx, exchange.RestSpot, bitmexEndpointOrderbookL2,
|
|
params,
|
|
&orderBooks)
|
|
}
|
|
|
|
// GetPositions returns positions
|
|
func (b *Bitmex) GetPositions(ctx context.Context, params PositionGetParams) ([]Position, error) {
|
|
var positions []Position
|
|
|
|
return positions, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodGet,
|
|
bitmexEndpointPosition,
|
|
params,
|
|
&positions)
|
|
}
|
|
|
|
// IsolatePosition enables isolated margin or cross margin per-position
|
|
func (b *Bitmex) IsolatePosition(ctx context.Context, params PositionIsolateMarginParams) (Position, error) {
|
|
var position Position
|
|
|
|
return position, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost,
|
|
bitmexEndpointIsolatePosition,
|
|
params,
|
|
&position)
|
|
}
|
|
|
|
// LeveragePosition chooses leverage for a position
|
|
func (b *Bitmex) LeveragePosition(ctx context.Context, params PositionUpdateLeverageParams) (Position, error) {
|
|
var position Position
|
|
|
|
return position, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost,
|
|
bitmexEndpointLeveragePosition,
|
|
params,
|
|
&position)
|
|
}
|
|
|
|
// UpdateRiskLimit updates risk limit on a position
|
|
func (b *Bitmex) UpdateRiskLimit(ctx context.Context, params PositionUpdateRiskLimitParams) (Position, error) {
|
|
var position Position
|
|
|
|
return position, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost,
|
|
bitmexEndpointAdjustRiskLimit,
|
|
params,
|
|
&position)
|
|
}
|
|
|
|
// TransferMargin transfers equity in or out of a position
|
|
func (b *Bitmex) TransferMargin(ctx context.Context, params PositionTransferIsolatedMarginParams) (Position, error) {
|
|
var position Position
|
|
|
|
return position, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost,
|
|
bitmexEndpointTransferMargin,
|
|
params,
|
|
&position)
|
|
}
|
|
|
|
// GetQuotes returns quotations
|
|
func (b *Bitmex) GetQuotes(ctx context.Context, params *GenericRequestParams) ([]Quote, error) {
|
|
var quotations []Quote
|
|
|
|
return quotations, b.SendHTTPRequest(ctx, exchange.RestSpot, bitmexEndpointQuote,
|
|
params,
|
|
"ations)
|
|
}
|
|
|
|
// GetQuotesByBuckets returns previous quotes in time buckets
|
|
func (b *Bitmex) GetQuotesByBuckets(ctx context.Context, params *QuoteGetBucketedParams) ([]Quote, error) {
|
|
var quotations []Quote
|
|
|
|
return quotations, b.SendHTTPRequest(ctx, exchange.RestSpot, bitmexEndpointQuoteBucketed,
|
|
params,
|
|
"ations)
|
|
}
|
|
|
|
// GetSettlementHistory returns settlement history
|
|
func (b *Bitmex) GetSettlementHistory(ctx context.Context, params *GenericRequestParams) ([]Settlement, error) {
|
|
var history []Settlement
|
|
|
|
return history, b.SendHTTPRequest(ctx, exchange.RestSpot, bitmexEndpointSettlement,
|
|
params,
|
|
&history)
|
|
}
|
|
|
|
// GetStats returns exchange wide per series turnover and volume statistics
|
|
func (b *Bitmex) GetStats(ctx context.Context) ([]Stats, error) {
|
|
var stats []Stats
|
|
|
|
return stats, b.SendHTTPRequest(ctx, exchange.RestSpot, bitmexEndpointStats, nil, &stats)
|
|
}
|
|
|
|
// GetStatsHistorical historic stats
|
|
func (b *Bitmex) GetStatsHistorical(ctx context.Context) ([]StatsHistory, error) {
|
|
var history []StatsHistory
|
|
|
|
return history, b.SendHTTPRequest(ctx, exchange.RestSpot, bitmexEndpointStatsHistory, nil, &history)
|
|
}
|
|
|
|
// GetStatSummary returns the stats summary in USD terms
|
|
func (b *Bitmex) GetStatSummary(ctx context.Context) ([]StatsUSD, error) {
|
|
var summary []StatsUSD
|
|
|
|
return summary, b.SendHTTPRequest(ctx, exchange.RestSpot, bitmexEndpointStatsSummary, nil, &summary)
|
|
}
|
|
|
|
// GetTrade returns executed trades on the desk
|
|
func (b *Bitmex) GetTrade(ctx context.Context, params *GenericRequestParams) ([]Trade, error) {
|
|
var trade []Trade
|
|
|
|
return trade, b.SendHTTPRequest(ctx, exchange.RestSpot, bitmexEndpointTrade, params, &trade)
|
|
}
|
|
|
|
// GetPreviousTrades previous trade history in time buckets
|
|
func (b *Bitmex) GetPreviousTrades(ctx context.Context, params *TradeGetBucketedParams) ([]Trade, error) {
|
|
var trade []Trade
|
|
|
|
return trade, b.SendHTTPRequest(ctx, exchange.RestSpot, bitmexEndpointTradeBucketed,
|
|
params,
|
|
&trade)
|
|
}
|
|
|
|
// GetUserInfo returns your user information
|
|
func (b *Bitmex) GetUserInfo(ctx context.Context) (User, error) {
|
|
var userInfo User
|
|
|
|
return userInfo, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodGet,
|
|
bitmexEndpointUser,
|
|
nil,
|
|
&userInfo)
|
|
}
|
|
|
|
// UpdateUserInfo updates user information
|
|
func (b *Bitmex) UpdateUserInfo(ctx context.Context, params *UserUpdateParams) (User, error) {
|
|
var userInfo User
|
|
|
|
return userInfo, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPut,
|
|
bitmexEndpointUser,
|
|
params,
|
|
&userInfo)
|
|
}
|
|
|
|
// GetAffiliateStatus returns your affiliate status
|
|
func (b *Bitmex) GetAffiliateStatus(ctx context.Context) (AffiliateStatus, error) {
|
|
var status AffiliateStatus
|
|
|
|
return status, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodGet,
|
|
bitmexEndpointUserAffiliate,
|
|
nil,
|
|
&status)
|
|
}
|
|
|
|
// CancelWithdraw cancels a current withdrawal
|
|
func (b *Bitmex) CancelWithdraw(ctx context.Context, token string) (TransactionInfo, error) {
|
|
var info TransactionInfo
|
|
|
|
return info, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost,
|
|
bitmexEndpointUserCancelWithdraw,
|
|
UserTokenParams{Token: token},
|
|
&info)
|
|
}
|
|
|
|
// CheckReferalCode checks a code, will return a percentage eg 0.1 for 10% or
|
|
// if err a 404
|
|
func (b *Bitmex) CheckReferalCode(ctx context.Context, referralCode string) (float64, error) {
|
|
var percentage float64
|
|
|
|
return percentage, b.SendHTTPRequest(ctx, exchange.RestSpot, bitmexEndpointUserCheckReferralCode,
|
|
UserCheckReferralCodeParams{ReferralCode: referralCode},
|
|
&percentage)
|
|
}
|
|
|
|
// GetUserCommision returns your account's commission status.
|
|
func (b *Bitmex) GetUserCommision(ctx context.Context) (UserCommission, error) {
|
|
var commissionInfo UserCommission
|
|
|
|
return commissionInfo, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodGet,
|
|
bitmexEndpointUserCommision,
|
|
nil,
|
|
&commissionInfo)
|
|
}
|
|
|
|
// ConfirmEmail confirms email address with a token
|
|
func (b *Bitmex) ConfirmEmail(ctx context.Context, token string) (ConfirmEmail, error) {
|
|
var confirmation ConfirmEmail
|
|
|
|
return confirmation, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodGet,
|
|
bitmexEndpointUserConfirmEmail,
|
|
UserTokenParams{Token: token},
|
|
&confirmation)
|
|
}
|
|
|
|
// ConfirmTwoFactorAuth confirms 2FA for this account.
|
|
func (b *Bitmex) ConfirmTwoFactorAuth(ctx context.Context, token, typ string) (bool, error) {
|
|
var working bool
|
|
|
|
return working, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost,
|
|
bitmexEndpointUserConfirmTFA,
|
|
UserConfirmTFAParams{Token: token, Type: typ},
|
|
&working)
|
|
}
|
|
|
|
// ConfirmWithdrawal confirms a withdrawal
|
|
func (b *Bitmex) ConfirmWithdrawal(ctx context.Context, token string) (TransactionInfo, error) {
|
|
var info TransactionInfo
|
|
|
|
return info, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost,
|
|
bitmexEndpointUserCancelWithdraw,
|
|
UserTokenParams{Token: token},
|
|
&info)
|
|
}
|
|
|
|
// GetCryptoDepositAddress returns a deposit address for a cryptocurency
|
|
func (b *Bitmex) GetCryptoDepositAddress(ctx context.Context, cryptoCurrency string) (string, error) {
|
|
var address string
|
|
|
|
if !strings.EqualFold(cryptoCurrency, currency.XBT.String()) {
|
|
return "",
|
|
fmt.Errorf("cryptocurrency %s deposits are not supported by exchange only bitcoin",
|
|
cryptoCurrency)
|
|
}
|
|
|
|
return address, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodGet,
|
|
bitmexEndpointUserDepositAddress,
|
|
UserCurrencyParams{Currency: "XBt"},
|
|
&address)
|
|
}
|
|
|
|
// DisableTFA dsiables 2 factor authentication for your account
|
|
func (b *Bitmex) DisableTFA(ctx context.Context, token, typ string) (bool, error) {
|
|
var disabled bool
|
|
|
|
return disabled, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost,
|
|
bitmexEndpointUserDisableTFA,
|
|
UserConfirmTFAParams{Token: token, Type: typ},
|
|
&disabled)
|
|
}
|
|
|
|
// UserLogOut logs you out of BitMEX
|
|
func (b *Bitmex) UserLogOut(ctx context.Context) error {
|
|
return b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost,
|
|
bitmexEndpointUserLogout,
|
|
nil,
|
|
nil)
|
|
}
|
|
|
|
// UserLogOutAll logs you out of all systems for BitMEX
|
|
func (b *Bitmex) UserLogOutAll(ctx context.Context) (int64, error) {
|
|
var status int64
|
|
|
|
return status, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost,
|
|
bitmexEndpointUserLogoutAll,
|
|
nil,
|
|
&status)
|
|
}
|
|
|
|
// GetUserMargin returns user margin information
|
|
func (b *Bitmex) GetUserMargin(ctx context.Context, currency string) (UserMargin, error) {
|
|
var info UserMargin
|
|
|
|
return info, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodGet,
|
|
bitmexEndpointUserMargin,
|
|
UserCurrencyParams{Currency: currency},
|
|
&info)
|
|
}
|
|
|
|
// GetAllUserMargin returns user margin information
|
|
func (b *Bitmex) GetAllUserMargin(ctx context.Context) ([]UserMargin, error) {
|
|
var info []UserMargin
|
|
|
|
return info, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodGet,
|
|
bitmexEndpointUserMargin,
|
|
UserCurrencyParams{Currency: "all"},
|
|
&info)
|
|
}
|
|
|
|
// GetMinimumWithdrawalFee returns minimum withdrawal fee information
|
|
func (b *Bitmex) GetMinimumWithdrawalFee(ctx context.Context, currency string) (MinWithdrawalFee, error) {
|
|
var fee MinWithdrawalFee
|
|
|
|
return fee, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodGet,
|
|
bitmexEndpointUserMinWithdrawalFee,
|
|
UserCurrencyParams{Currency: currency},
|
|
&fee)
|
|
}
|
|
|
|
// GetUserPreferences returns user preferences
|
|
func (b *Bitmex) GetUserPreferences(ctx context.Context, params UserPreferencesParams) (User, error) {
|
|
var userInfo User
|
|
|
|
return userInfo, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost,
|
|
bitmexEndpointUserPreferences,
|
|
params,
|
|
&userInfo)
|
|
}
|
|
|
|
// EnableTFA enables 2 factor authentication
|
|
func (b *Bitmex) EnableTFA(ctx context.Context, typ string) (bool, error) {
|
|
var enabled bool
|
|
|
|
return enabled, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost,
|
|
bitmexEndpointUserRequestTFA,
|
|
UserConfirmTFAParams{Type: typ},
|
|
&enabled)
|
|
}
|
|
|
|
// UserRequestWithdrawal This will send a confirmation email to the email
|
|
// address on record, unless requested via an API Key with the withdraw
|
|
// permission.
|
|
func (b *Bitmex) UserRequestWithdrawal(ctx context.Context, params UserRequestWithdrawalParams) (TransactionInfo, error) {
|
|
var info TransactionInfo
|
|
|
|
return info, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost,
|
|
bitmexEndpointUserRequestWithdraw,
|
|
params,
|
|
&info)
|
|
}
|
|
|
|
// GetWalletInfo returns user wallet information
|
|
func (b *Bitmex) GetWalletInfo(ctx context.Context, currency string) (WalletInfo, error) {
|
|
var info WalletInfo
|
|
|
|
if err := b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodGet,
|
|
bitmexEndpointUserWallet,
|
|
UserCurrencyParams{Currency: currency},
|
|
&info); err != nil {
|
|
return info, err
|
|
}
|
|
|
|
// Bitmex has an "interesting" of dealing with currencies,
|
|
// for instance XBt is actually BTC but in Satoshi units,
|
|
// for sanity purposes apply here a conversion to normalize
|
|
// this
|
|
// avoid a copy here since this is a big struct
|
|
normalizeWalletInfo(&info)
|
|
|
|
return info, nil
|
|
}
|
|
|
|
// GetWalletHistory returns user wallet history transaction data
|
|
func (b *Bitmex) GetWalletHistory(ctx context.Context, currency string) ([]TransactionInfo, error) {
|
|
var info []TransactionInfo
|
|
|
|
return info, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodGet,
|
|
bitmexEndpointUserWalletHistory,
|
|
UserCurrencyParams{Currency: currency},
|
|
&info)
|
|
}
|
|
|
|
// GetWalletSummary returns user wallet summary
|
|
func (b *Bitmex) GetWalletSummary(ctx context.Context, currency string) ([]TransactionInfo, error) {
|
|
var info []TransactionInfo
|
|
|
|
return info, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodGet,
|
|
bitmexEndpointUserWalletSummary,
|
|
UserCurrencyParams{Currency: currency},
|
|
&info)
|
|
}
|
|
|
|
// SendHTTPRequest sends an unauthenticated HTTP request
|
|
func (b *Bitmex) SendHTTPRequest(ctx context.Context, ep exchange.URL, path string, params Parameter, result interface{}) error {
|
|
var respCheck interface{}
|
|
endpoint, err := b.API.Endpoints.GetURL(ep)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
path = endpoint + path
|
|
if params != nil && !params.IsNil() {
|
|
path, err = params.ToURLVals(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
item := &request.Item{
|
|
Method: http.MethodGet,
|
|
Path: path,
|
|
Result: &respCheck,
|
|
Verbose: b.Verbose,
|
|
HTTPDebugging: b.HTTPDebugging,
|
|
HTTPRecording: b.HTTPRecording,
|
|
}
|
|
|
|
err = b.SendPayload(ctx, request.Unset, func() (*request.Item, error) {
|
|
return item, nil
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return b.CaptureError(respCheck, result)
|
|
}
|
|
|
|
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request to bitmex
|
|
func (b *Bitmex) SendAuthenticatedHTTPRequest(ctx context.Context, ep exchange.URL, verb, path string, params Parameter, result interface{}) error {
|
|
if !b.AllowAuthenticatedRequest() {
|
|
return fmt.Errorf("%s %w", b.Name, exchange.ErrAuthenticatedRequestWithoutCredentialsSet)
|
|
}
|
|
endpoint, err := b.API.Endpoints.GetURL(ep)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var respCheck interface{}
|
|
newRequest := func() (*request.Item, error) {
|
|
expires := time.Now().Add(time.Second * 10)
|
|
timestamp := expires.UnixNano()
|
|
timestampStr := strconv.FormatInt(timestamp, 10)
|
|
timestampNew := timestampStr[:13]
|
|
|
|
headers := make(map[string]string)
|
|
headers["Content-Type"] = "application/json"
|
|
headers["api-expires"] = timestampNew
|
|
headers["api-key"] = b.API.Credentials.Key
|
|
|
|
var payload string
|
|
if params != nil {
|
|
err = params.VerifyData()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var data []byte
|
|
data, err = json.Marshal(params)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
payload = string(data)
|
|
}
|
|
|
|
var hmac []byte
|
|
hmac, err = crypto.GetHMAC(crypto.HashSHA256,
|
|
[]byte(verb+"/api/v1"+path+timestampNew+payload),
|
|
[]byte(b.API.Credentials.Secret))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
headers["api-signature"] = crypto.HexEncodeToString(hmac)
|
|
|
|
return &request.Item{
|
|
Method: verb,
|
|
Path: endpoint + path,
|
|
Headers: headers,
|
|
Body: strings.NewReader(payload),
|
|
Result: &respCheck,
|
|
AuthRequest: true,
|
|
Verbose: b.Verbose,
|
|
HTTPDebugging: b.HTTPDebugging,
|
|
HTTPRecording: b.HTTPRecording,
|
|
}, nil
|
|
}
|
|
err = b.SendPayload(ctx, request.Auth, newRequest)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return b.CaptureError(respCheck, result)
|
|
}
|
|
|
|
// CaptureError little hack that captures an error
|
|
func (b *Bitmex) CaptureError(resp, reType interface{}) error {
|
|
var Error RequestError
|
|
|
|
marshalled, err := json.Marshal(resp)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = json.Unmarshal(marshalled, &Error)
|
|
if err == nil && Error.Error.Name != "" {
|
|
return fmt.Errorf("bitmex error %s: %s",
|
|
Error.Error.Name,
|
|
Error.Error.Message)
|
|
}
|
|
|
|
return json.Unmarshal(marshalled, reType)
|
|
}
|
|
|
|
// GetFee returns an estimate of fee based on type of transaction
|
|
func (b *Bitmex) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) {
|
|
var fee float64
|
|
var err error
|
|
switch feeBuilder.FeeType {
|
|
case exchange.CryptocurrencyTradeFee:
|
|
fee = calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount, feeBuilder.IsMaker)
|
|
case exchange.OfflineTradeFee:
|
|
fee = getOfflineTradeFee(feeBuilder.PurchasePrice, feeBuilder.Amount)
|
|
}
|
|
if fee < 0 {
|
|
fee = 0
|
|
}
|
|
return fee, err
|
|
}
|
|
|
|
// getOfflineTradeFee calculates the worst case-scenario trading fee
|
|
func getOfflineTradeFee(price, amount float64) float64 {
|
|
return 0.000750 * price * amount
|
|
}
|
|
|
|
// calculateTradingFee returns the fee for trading any currency on Bittrex
|
|
func calculateTradingFee(purchasePrice, amount float64, isMaker bool) float64 {
|
|
var fee = 0.000750
|
|
if isMaker {
|
|
fee -= 0.000250
|
|
}
|
|
|
|
return fee * purchasePrice * amount
|
|
}
|
|
|
|
// normalizeWalletInfo converts any non-standard currencies (eg. XBt -> BTC)
|
|
func normalizeWalletInfo(w *WalletInfo) {
|
|
if w.Currency != "XBt" {
|
|
return
|
|
}
|
|
|
|
w.Currency = "BTC"
|
|
w.Amount *= constSatoshiBTC
|
|
}
|