fixed merge conflicts

This commit is contained in:
Ermal Guni
2018-08-09 23:46:37 +02:00
58 changed files with 13581 additions and 2062 deletions

View File

@@ -4,9 +4,9 @@ thrasher- | https://github.com/thrasher-
shazbert | https://github.com/shazbert
gloriousCode | https://github.com/gloriousCode
140am | https://github.com/140am
ermalguni | https://github.com/ermalguni
marcofranssen | https://github.com/marcofranssen
Betazoid | https://github.com/Betazoid
ermalguni | https://github.com/ermalguni
crackcomm | https://github.com/crackcomm
bretep | https://github.com/bretep
gam-phon | https://github.com/gam-phon

View File

@@ -24,6 +24,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
| Bitfinex | Yes | Yes | NA |
| Bitflyer | Yes | No | NA |
| Bithumb | Yes | NA | NA |
| BitMEX | Yes | No | NA |
| Bitstamp | Yes | Yes | No |
| Bittrex | Yes | No | NA |
| BTCC | Yes | Yes | No |
@@ -147,13 +148,13 @@ Binaries will be published once the codebase reaches a stable condition.
|User|Github|Contribution Amount|
|--|--|--|
| thrasher- | https://github.com/thrasher- | 453 |
| shazbert | https://github.com/shazbert | 141 |
| thrasher- | https://github.com/thrasher- | 456 |
| shazbert | https://github.com/shazbert | 142 |
| gloriousCode | https://github.com/gloriousCode | 122 |
| 140am | https://github.com/140am | 8 |
| ermalguni | https://github.com/ermalguni | 4 |
| marcofranssen | https://github.com/marcofranssen | 4 |
| Betazoid | https://github.com/Betazoid | 4 |
| ermalguni | https://github.com/ermalguni | 3 |
| crackcomm | https://github.com/crackcomm | 3 |
| bretep | https://github.com/bretep | 2 |
| gam-phon | https://github.com/gam-phon | 2 |
@@ -175,6 +176,3 @@ Binaries will be published once the codebase reaches a stable condition.
| askew- | https://github.com/askew- | 1 |
| whilei | https://github.com/whilei | 1 |
| snipesjr | https://github.com/snipesjr | 1 |

View File

@@ -33,8 +33,8 @@ const (
configMaxAuthFailres = 3
)
// Variables here are mainly alerts and a configuration object
var (
// Constants here hold some messages
const (
ErrExchangeNameEmpty = "Exchange #%d in config: Exchange name is empty."
ErrExchangeAvailablePairsEmpty = "Exchange %s: Available pairs is empty."
ErrExchangeEnabledPairsEmpty = "Exchange %s: Enabled pairs is empty."
@@ -54,166 +54,171 @@ var (
WarningExchangeAuthAPIDefaultOrEmptyValues = "WARNING -- Exchange %s: Authenticated API support disabled due to default/empty APIKey/Secret/ClientID values."
WarningCurrencyExchangeProvider = "WARNING -- Currency exchange provider invalid valid. Reset to Fixer."
WarningPairsLastUpdatedThresholdExceeded = "WARNING -- Exchange %s: Last manual update of available currency pairs has exceeded %d days. Manual update required!"
Cfg Config
IsInitialSetup bool
testBypass bool
m sync.Mutex
)
// Variables here are used for configuration
var (
Cfg Config
IsInitialSetup bool
testBypass bool
m sync.Mutex
)
// WebserverConfig struct holds the prestart variables for the webserver.
type WebserverConfig struct {
Enabled bool
AdminUsername string
AdminPassword string
ListenAddress string
WebsocketConnectionLimit int
WebsocketMaxAuthFailures int
WebsocketAllowInsecureOrigin bool
Enabled bool `json:"enabled"`
AdminUsername string `json:"adminUsername"`
AdminPassword string `json:"adminPassword"`
ListenAddress string `json:"listenAddress"`
WebsocketConnectionLimit int `json:"websocketConnectionLimit"`
WebsocketMaxAuthFailures int `json:"websocketMaxAuthFailures"`
WebsocketAllowInsecureOrigin bool `json:"websocketAllowInsecureOrigin"`
}
// Post holds the bot configuration data
type Post struct {
Data Config `json:"Data"`
Data Config `json:"data"`
}
// CurrencyPairFormatConfig stores the users preferred currency pair display
type CurrencyPairFormatConfig struct {
Uppercase bool
Delimiter string `json:",omitempty"`
Separator string `json:",omitempty"`
Index string `json:",omitempty"`
Uppercase bool `json:"uppercase"`
Delimiter string `json:"delimiter,omitempty"`
Separator string `json:"separator,omitempty"`
Index string `json:"index,omitempty"`
}
// Config is the overarching object that holds all the information for
// prestart management of Portfolio, Communications, Webserver and Enabled
// Exchanges
type Config struct {
Name string
EncryptConfig int
GlobalHTTPTimeout time.Duration `json:"GlobalHTTPTimeout"`
Currency CurrencyConfig `json:"CurrencyConfig"`
Communications CommunicationsConfig `json:"Communications"`
Portfolio portfolio.Base `json:"PortfolioAddresses"`
Webserver WebserverConfig `json:"Webserver"`
Exchanges []ExchangeConfig `json:"Exchanges"`
BankAccounts []BankAccount `json:"BankAccounts"`
Name string `json:"name"`
EncryptConfig int `json:"encryptConfig"`
GlobalHTTPTimeout time.Duration `json:"globalHTTPTimeout"`
Currency CurrencyConfig `json:"currencyConfig"`
Communications CommunicationsConfig `json:"communications"`
Portfolio portfolio.Base `json:"portfolioAddresses"`
Webserver WebserverConfig `json:"webserver"`
Exchanges []ExchangeConfig `json:"exchanges"`
BankAccounts []BankAccount `json:"bankAccounts"`
// Deprecated config settings, will be removed at a future date
CurrencyPairFormat *CurrencyPairFormatConfig `json:"CurrencyPairFormat,omitempty"`
FiatDisplayCurrency string `json:"FiatDispayCurrency,omitempty"`
Cryptocurrencies string `json:"Cryptocurrencies,omitempty"`
SMS *SMSGlobalConfig `json:"SMSGlobal,omitempty"`
CurrencyPairFormat *CurrencyPairFormatConfig `json:"currencyPairFormat,omitempty"`
FiatDisplayCurrency string `json:"fiatDispayCurrency,omitempty"`
Cryptocurrencies string `json:"cryptocurrencies,omitempty"`
SMS *SMSGlobalConfig `json:"smsGlobal,omitempty"`
}
// ExchangeConfig holds all the information needed for each enabled Exchange.
type ExchangeConfig struct {
Name string
Enabled bool
Verbose bool
Websocket bool
UseSandbox bool
RESTPollingDelay time.Duration
HTTPTimeout time.Duration
AuthenticatedAPISupport bool
APIKey string
APISecret string
APIAuthPEMKey string `json:",omitempty"`
ClientID string `json:",omitempty"`
AvailablePairs string
EnabledPairs string
BaseCurrencies string
AssetTypes string
SupportsAutoPairUpdates bool
PairsLastUpdated int64 `json:",omitempty"`
ConfigCurrencyPairFormat *CurrencyPairFormatConfig `json:"ConfigCurrencyPairFormat"`
RequestCurrencyPairFormat *CurrencyPairFormatConfig `json:"RequestCurrencyPairFormat"`
BankAccounts []BankAccount
Name string `json:"name"`
Enabled bool `json:"enabled"`
Verbose bool `json:"verbose"`
Websocket bool `json:"websocket"`
UseSandbox bool `json:"useSandbox"`
RESTPollingDelay time.Duration `json:"restPollingDelay"`
HTTPTimeout time.Duration `json:"httpTimeout"`
HTTPUserAgent string `json:"httpUserAgent"`
AuthenticatedAPISupport bool `json:"authenticatedApiSupport"`
APIKey string `json:"apiKey"`
APISecret string `json:"apiSecret"`
APIAuthPEMKey string `json:"apiAuthPemKey,omitempty"`
ClientID string `json:"clientId,omitempty"`
AvailablePairs string `json:"availablePairs"`
EnabledPairs string `json:"enabledPairs"`
BaseCurrencies string `json:"baseCurrencies"`
AssetTypes string `json:"assetTypes"`
SupportsAutoPairUpdates bool `json:"supportsAutoPairUpdates"`
PairsLastUpdated int64 `json:"pairsLastUpdated,omitempty"`
ConfigCurrencyPairFormat *CurrencyPairFormatConfig `json:"configCurrencyPairFormat"`
RequestCurrencyPairFormat *CurrencyPairFormatConfig `json:"requestCurrencyPairFormat"`
BankAccounts []BankAccount `json:"bankAccounts"`
}
// BankAccount holds differing bank account details by supported funding
// currency
type BankAccount struct {
Enabled bool `json:",omitempty"`
BankName string
BankAddress string
AccountName string
AccountNumber string
SWIFTCode string
IBAN string
BSBNumber string `json:",omitempty"`
SupportedCurrencies string
SupportedExchanges string `json:",omitempty"`
Enabled bool `json:",omitempty"`
BankName string `json:"bankName"`
BankAddress string `json:"bankAddress"`
AccountName string `json:"accountName"`
AccountNumber string `json:"accountNumber"`
SWIFTCode string `json:"swiftCode"`
IBAN string `json:"iban"`
BSBNumber string `json:"bsbNumber,omitempty"`
SupportedCurrencies string `json:"supportedCurrencies"`
SupportedExchanges string `json:"supportedExchanges,omitempty"`
}
// BankTransaction defines a related banking transaction
type BankTransaction struct {
ReferenceNumber string
TransactionNumber string
PaymentInstructions string
ReferenceNumber string `json:"referenceNumber"`
TransactionNumber string `json:"transactionNumber"`
PaymentInstructions string `json:"paymentInstructions"`
}
// CurrencyConfig holds all the information needed for currency related manipulation
type CurrencyConfig struct {
ForexProviders []base.Settings `json:"ForexProviders"`
Cryptocurrencies string `json:"Cryptocurrencies"`
CurrencyPairFormat *CurrencyPairFormatConfig `json:"CurrencyPairFormat"`
FiatDisplayCurrency string
ForexProviders []base.Settings `json:"forexProviders"`
Cryptocurrencies string `json:"cryptocurrencies"`
CurrencyPairFormat *CurrencyPairFormatConfig `json:"currencyPairFormat"`
FiatDisplayCurrency string `json:"fiatDisplayCurrency"`
}
// CommunicationsConfig holds all the information needed for each
// enabled communication package
type CommunicationsConfig struct {
SlackConfig SlackConfig `json:"Slack"`
SMSGlobalConfig SMSGlobalConfig `json:"SMSGlobal"`
SMTPConfig SMTPConfig `json:"SMTP"`
TelegramConfig TelegramConfig `json:"Telegram"`
SlackConfig SlackConfig `json:"slack"`
SMSGlobalConfig SMSGlobalConfig `json:"smsGlobal"`
SMTPConfig SMTPConfig `json:"smtp"`
TelegramConfig TelegramConfig `json:"telegram"`
}
// SlackConfig holds all variables to start and run the Slack package
type SlackConfig struct {
Name string `json:"Name"`
Enabled bool `json:"Enabled"`
Verbose bool `json:"Verbose"`
TargetChannel string `json:"TargetChannel"`
VerificationToken string `json:"VerificationToken"`
Name string `json:"name"`
Enabled bool `json:"enabled"`
Verbose bool `json:"verbose"`
TargetChannel string `json:"targetChannel"`
VerificationToken string `json:"verificationToken"`
}
// SMSContact stores the SMS contact info
type SMSContact struct {
Name string `json:"Name"`
Number string `json:"Number"`
Enabled bool `json:"Enabled"`
Name string `json:"name"`
Number string `json:"number"`
Enabled bool `json:"enabled"`
}
// SMSGlobalConfig structure holds all the variables you need for instant
// messaging and broadcast used by SMSGlobal
type SMSGlobalConfig struct {
Name string `json:"Name"`
Enabled bool `json:"Enabled"`
Verbose bool `json:"Verbose"`
Username string `json:"Username"`
Password string `json:"Password"`
Contacts []SMSContact `json:"Contacts"`
Name string `json:"name"`
Enabled bool `json:"enabled"`
Verbose bool `json:"verbose"`
Username string `json:"username"`
Password string `json:"password"`
Contacts []SMSContact `json:"contacts"`
}
// SMTPConfig holds all variables to start and run the SMTP package
type SMTPConfig struct {
Name string `json:"Name"`
Enabled bool `json:"Enabled"`
Verbose bool `json:"Verbose"`
Host string `json:"Host"`
Port string `json:"Port"`
AccountName string `json:"AccountName"`
AccountPassword string `json:"AccountPassword"`
RecipientList string `json:"RecipientList"`
Name string `json:"name"`
Enabled bool `json:"enabled"`
Verbose bool `json:"verbose"`
Host string `json:"host"`
Port string `json:"port"`
AccountName string `json:"accountName"`
AccountPassword string `json:"accountPassword"`
RecipientList string `json:"recipientList"`
}
// TelegramConfig holds all variables to start and run the Telegram package
type TelegramConfig struct {
Name string `json:"Name"`
Enabled bool `json:"Enabled"`
Verbose bool `json:"Verbose"`
VerificationToken string `json:"VerificationToken"`
Name string `json:"name"`
Enabled bool `json:"enabled"`
Verbose bool `json:"verbose"`
VerificationToken string `json:"verificationToken"`
}
// GetCurrencyConfig returns currency configurations

View File

@@ -206,7 +206,7 @@ func TestGetEnabledExchanges(t *testing.T) {
}
exchanges := cfg.GetEnabledExchanges()
if len(exchanges) != 29 {
if len(exchanges) != 30 {
t.Error(
"Test failed. TestGetEnabledExchanges. Enabled exchanges value mismatch",
)
@@ -258,7 +258,7 @@ func TestGetDisabledExchanges(t *testing.T) {
}
func TestCountEnabledExchanges(t *testing.T) {
defaultEnabledExchanges := 29
defaultEnabledExchanges := 30
GetConfigEnabledExchanges := GetConfig()
err := GetConfigEnabledExchanges.LoadConfig(ConfigTestFile)
if err != nil {

File diff suppressed because one or more lines are too long

View File

@@ -12,6 +12,7 @@ import (
"github.com/thrasher-/gocryptotrader/exchanges/bitfinex"
"github.com/thrasher-/gocryptotrader/exchanges/bitflyer"
"github.com/thrasher-/gocryptotrader/exchanges/bithumb"
"github.com/thrasher-/gocryptotrader/exchanges/bitmex"
"github.com/thrasher-/gocryptotrader/exchanges/bitstamp"
"github.com/thrasher-/gocryptotrader/exchanges/bittrex"
"github.com/thrasher-/gocryptotrader/exchanges/btcc"
@@ -145,6 +146,8 @@ func LoadExchange(name string, useWG bool, wg *sync.WaitGroup) error {
exch = new(bitflyer.Bitflyer)
case "bithumb":
exch = new(bithumb.Bithumb)
case "bitmex":
exch = new(bitmex.Bitmex)
case "bitstamp":
exch = new(bitstamp.Bitstamp)
case "bittrex":

View File

@@ -70,6 +70,7 @@ func (a *ANX) Setup(exch config.ExchangeConfig) {
a.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
a.SetAPIKeys(exch.APIKey, exch.APISecret, "", true)
a.SetHTTPClientTimeout(exch.HTTPTimeout)
a.SetHTTPClientUserAgent(exch.HTTPUserAgent)
a.RESTPollingDelay = exch.RESTPollingDelay
a.Verbose = exch.Verbose
a.Websocket = exch.Websocket

View File

@@ -83,6 +83,7 @@ func (b *Binance) Setup(exch config.ExchangeConfig) {
b.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
b.SetAPIKeys(exch.APIKey, exch.APISecret, "", false)
b.SetHTTPClientTimeout(exch.HTTPTimeout)
b.SetHTTPClientUserAgent(exch.HTTPUserAgent)
b.RESTPollingDelay = exch.RESTPollingDelay
b.Verbose = exch.Verbose
b.Websocket = exch.Websocket

View File

@@ -114,6 +114,7 @@ func (b *Bitfinex) Setup(exch config.ExchangeConfig) {
b.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
b.SetAPIKeys(exch.APIKey, exch.APISecret, "", false)
b.SetHTTPClientTimeout(exch.HTTPTimeout)
b.SetHTTPClientUserAgent(exch.HTTPUserAgent)
b.RESTPollingDelay = exch.RESTPollingDelay
b.Verbose = exch.Verbose
b.Websocket = exch.Websocket

View File

@@ -100,6 +100,7 @@ func (b *Bitflyer) Setup(exch config.ExchangeConfig) {
b.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
b.SetAPIKeys(exch.APIKey, exch.APISecret, "", false)
b.SetHTTPClientTimeout(exch.HTTPTimeout)
b.SetHTTPClientUserAgent(exch.HTTPUserAgent)
b.RESTPollingDelay = exch.RESTPollingDelay
b.Verbose = exch.Verbose
b.Websocket = exch.Websocket

View File

@@ -82,6 +82,7 @@ func (b *Bithumb) Setup(exch config.ExchangeConfig) {
b.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
b.SetAPIKeys(exch.APIKey, exch.APISecret, "", false)
b.SetHTTPClientTimeout(exch.HTTPTimeout)
b.SetHTTPClientUserAgent(exch.HTTPUserAgent)
b.RESTPollingDelay = exch.RESTPollingDelay
b.Verbose = exch.Verbose
b.Websocket = exch.Websocket

133
exchanges/bitmex/README.md Normal file
View File

@@ -0,0 +1,133 @@
# GoCryptoTrader package Bitmex
<img src="https://github.com/thrasher-/gocryptotrader/blob/master/web/src/assets/page-logo.png?raw=true" width="350px" height="350px" hspace="70">
[![Build Status](https://travis-ci.org/thrasher-/gocryptotrader.svg?branch=master)](https://travis-ci.org/thrasher-/gocryptotrader)
[![Software License](https://img.shields.io/badge/License-MIT-orange.svg?style=flat-square)](https://github.com/thrasher-/gocryptotrader/blob/master/LICENSE)
[![GoDoc](https://godoc.org/github.com/thrasher-/gocryptotrader?status.svg)](https://godoc.org/github.com/thrasher-/gocryptotrader/exchanges/bitmex)
[![Coverage Status](http://codecov.io/github/thrasher-/gocryptotrader/coverage.svg?branch=master)](http://codecov.io/github/thrasher-/gocryptotrader?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/thrasher-/gocryptotrader)](https://goreportcard.com/report/github.com/thrasher-/gocryptotrader)
This bitmex package is part of the GoCryptoTrader codebase.
## This is still in active development
You can track ideas, planned features and what's in progresss on this Trello board: [https://trello.com/b/ZAhMhpOy/gocryptotrader](https://trello.com/b/ZAhMhpOy/gocryptotrader).
Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader Slack](https://gocryptotrader.herokuapp.com/)
## Bithumb Exchange
### Current Features
+ REST Support
### How to enable
+ [Enable via configuration](https://github.com/thrasher-/gocryptotrader/tree/master/config#enable-exchange-via-config-example)
+ Individual package example below:
```go
// Exchanges will be abstracted out in further updates and examples will be
// supplied then
```
### How to do REST public/private calls
+ If enabled via "configuration".json file the exchange will be added to the
IBotExchange array in the ```go var bot Bot``` and you will only be able to use
the wrapper interface functions for accessing exchange data. View routines.go
for an example of integration usage with GoCryptoTrader. Rudimentary example
below:
main.go
```go
var b exchange.IBotExchange
for i := range bot.exchanges {
if bot.exchanges[i].GetName() == "Bitmex" {
b = bot.exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
tick, err := b.GetTickerPrice()
if err != nil {
// Handle error
}
// Fetches current orderbook information
ob, err := b.GetOrderbookEx()
if err != nil {
// Handle error
}
// Private calls - wrapper functions - make sure your APIKEY and APISECRET are
// set and AuthenticatedAPISupport is set to true
// Fetches current account information
accountInfo, err := b.GetExchangeAccountInfo()
if err != nil {
// Handle error
}
```
+ If enabled via individually importing package, rudimentary example below:
```go
// Public calls
// Fetches current ticker information
ticker, err := b.GetTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
ob, err := b.GetOrderBook()
if err != nil {
// Handle error
}
// Private calls - make sure your APIKEY and APISECRET are set and
// AuthenticatedAPISupport is set to true
// GetUserInfo returns account info
accountInfo, err := b.GetUserInfo(...)
if err != nil {
// Handle error
}
// Submits an order and the exchange and returns its tradeID
tradeID, err := b.Trade(...)
if err != nil {
// Handle error
}
```
### Please click GoDocs chevron above to view current GoDoc information for this package
## Contribution
Please feel free to submit any pull requests or suggest any desired features to be added.
When submitting a PR, please abide by our coding guidelines:
+ Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting) guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)).
+ Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary) guidelines.
+ Code must adhere to our [coding style](https://github.com/thrasher-/gocryptotrader/blob/master/doc/coding_style.md).
+ Pull requests need to be based on and opened against the `master` branch.
## Donations
<img src="https://github.com/thrasher-/gocryptotrader/blob/master/web/src/assets/donate.png?raw=true" hspace="70">
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
***1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB***

893
exchanges/bitmex/bitmex.go Normal file
View File

@@ -0,0 +1,893 @@
package bitmex
import (
"bytes"
"encoding/json"
"fmt"
"log"
"strconv"
"time"
"github.com/gorilla/websocket"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
// Bitmex is the overarching type across this package
type Bitmex struct {
exchange.Base
WebsocketConn *websocket.Conn
shutdown *Shutdown
}
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"
// Rate limits - 150 requests per 5 minutes
bitmexUnauthRate = 30
// 300 requests per 5 minutes
bitmexAuthRate = 40
// ContractPerpetual perpetual contract type
ContractPerpetual = iota
// ContractFutures futures contract type
ContractFutures
// ContractDownsideProfit downside profit contract type
ContractDownsideProfit
// ContractUpsideProfit upside profit contract type
ContractUpsideProfit
)
// SetDefaults sets the basic defaults for Bitmex
func (b *Bitmex) SetDefaults() {
b.Name = "Bitmex"
b.Enabled = false
b.Verbose = false
b.Websocket = false
b.RESTPollingDelay = 10
b.RequestCurrencyPairFormat.Delimiter = ""
b.RequestCurrencyPairFormat.Uppercase = true
b.ConfigCurrencyPairFormat.Delimiter = ""
b.ConfigCurrencyPairFormat.Uppercase = true
b.AssetTypes = []string{ticker.Spot}
b.Requester = request.New(b.Name,
request.NewRateLimit(time.Second, bitmexAuthRate),
request.NewRateLimit(time.Second, bitmexUnauthRate),
common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout))
b.shutdown = b.NewRoutineManagement()
}
// Setup takes in the supplied exchange configuration details and sets params
func (b *Bitmex) Setup(exch config.ExchangeConfig) {
if !exch.Enabled {
b.SetEnabled(false)
} else {
b.Enabled = true
b.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
b.SetAPIKeys(exch.APIKey, exch.APISecret, "", false)
b.RESTPollingDelay = exch.RESTPollingDelay
b.Verbose = exch.Verbose
b.Websocket = exch.Websocket
b.BaseCurrencies = common.SplitStrings(exch.BaseCurrencies, ",")
b.AvailablePairs = common.SplitStrings(exch.AvailablePairs, ",")
b.EnabledPairs = common.SplitStrings(exch.EnabledPairs, ",")
err := b.SetCurrencyPairFormat()
if err != nil {
log.Fatal(err)
}
err = b.SetAssetTypes()
if err != nil {
log.Fatal(err)
}
}
}
// GetAnnouncement returns the general announcements from Bitmex
func (b *Bitmex) GetAnnouncement() ([]Announcement, error) {
var announcement []Announcement
return announcement, b.SendHTTPRequest(bitmexEndpointAnnouncement,
nil,
&announcement)
}
// GetUrgentAnnouncement returns an urgent announcement for your account
func (b *Bitmex) GetUrgentAnnouncement() ([]Announcement, error) {
var announcement []Announcement
return announcement, b.SendAuthenticatedHTTPRequest("GET",
bitmexEndpointAnnouncementUrgent,
nil,
&announcement)
}
// GetAPIKeys returns the APIkeys from bitmex
func (b *Bitmex) GetAPIKeys() ([]APIKey, error) {
var keys []APIKey
return keys, b.SendAuthenticatedHTTPRequest("GET",
bitmexEndpointAPIkeys,
nil,
&keys)
}
// RemoveAPIKey removes an Apikey from the bitmex trading engine
func (b *Bitmex) RemoveAPIKey(params APIKeyParams) (bool, error) {
var keyDeleted bool
return keyDeleted, b.SendAuthenticatedHTTPRequest("DELETE",
bitmexEndpointAPIkeys,
params,
&keyDeleted)
}
// DisableAPIKey disables an Apikey from the bitmex trading engine
func (b *Bitmex) DisableAPIKey(params APIKeyParams) (APIKey, error) {
var keyInfo APIKey
return keyInfo, b.SendAuthenticatedHTTPRequest("POST",
bitmexEndpointDisableAPIkey,
params,
&keyInfo)
}
// EnableAPIKey enables an Apikey from the bitmex trading engine
func (b *Bitmex) EnableAPIKey(params APIKeyParams) (APIKey, error) {
var keyInfo APIKey
return keyInfo, b.SendAuthenticatedHTTPRequest("POST",
bitmexEndpointEnableAPIkey,
params,
&keyInfo)
}
// GetTrollboxMessages returns messages from the bitmex trollbox
func (b *Bitmex) GetTrollboxMessages(params ChatGetParams) ([]Chat, error) {
var messages []Chat
return messages, b.SendHTTPRequest(bitmexEndpointTrollbox, params, &messages)
}
// SendTrollboxMessage sends a message to the bitmex trollbox
func (b *Bitmex) SendTrollboxMessage(params ChatSendParams) ([]Chat, error) {
var messages []Chat
return messages, b.SendAuthenticatedHTTPRequest("POST",
bitmexEndpointTrollboxSend,
params,
&messages)
}
// GetTrollboxChannels the channels from the the bitmex trollbox
func (b *Bitmex) GetTrollboxChannels() ([]ChatChannel, error) {
var channels []ChatChannel
return channels, b.SendHTTPRequest(bitmexEndpointTrollboxChannels,
nil,
&channels)
}
// GetTrollboxConnectedUsers the channels from the the bitmex trollbox
func (b *Bitmex) GetTrollboxConnectedUsers() (ConnectedUsers, error) {
var users ConnectedUsers
return users, b.SendHTTPRequest(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(params GenericRequestParams) ([]Execution, error) {
var executionList []Execution
return executionList, b.SendAuthenticatedHTTPRequest("GET",
bitmexEndpointExecution,
params,
&executionList)
}
// GetAccountExecutionTradeHistory returns all balance-affecting executions.
// This includes each trade, insurance charge, and settlement.
func (b *Bitmex) GetAccountExecutionTradeHistory(params GenericRequestParams) ([]Execution, error) {
var tradeHistory []Execution
return tradeHistory, b.SendAuthenticatedHTTPRequest("GET",
bitmexEndpointExecutionTradeHistory,
params,
&tradeHistory)
}
// GetFundingHistory returns funding history
func (b *Bitmex) GetFundingHistory() ([]Funding, error) {
var fundingHistory []Funding
return fundingHistory, b.SendHTTPRequest(bitmexEndpointFundingHistory,
nil,
&fundingHistory)
}
// GetInstruments returns instrument data
func (b *Bitmex) GetInstruments(params GenericRequestParams) ([]Instrument, error) {
var instruments []Instrument
return instruments, b.SendHTTPRequest(bitmexEndpointInstruments,
params,
&instruments)
}
// GetActiveInstruments returns active instruments
func (b *Bitmex) GetActiveInstruments(params GenericRequestParams) ([]Instrument, error) {
var activeInstruments []Instrument
return activeInstruments, b.SendHTTPRequest(bitmexEndpointActiveInstruments,
params,
&activeInstruments)
}
// GetActiveAndIndexInstruments returns all active instruments and all indices
func (b *Bitmex) GetActiveAndIndexInstruments() ([]Instrument, error) {
var activeAndIndices []Instrument
return activeAndIndices,
b.SendHTTPRequest(bitmexEndpointActiveAndIndexInstruments,
nil,
&activeAndIndices)
}
// GetActiveIntervals returns funding history
func (b *Bitmex) GetActiveIntervals() (InstrumentInterval, error) {
var interval InstrumentInterval
return interval, b.SendHTTPRequest(bitmexEndpointActiveIntervals,
nil,
&interval)
}
// GetCompositeIndex returns composite index
func (b *Bitmex) GetCompositeIndex(params GenericRequestParams) ([]IndexComposite, error) {
var compositeIndices []IndexComposite
return compositeIndices, b.SendHTTPRequest(bitmexEndpointCompositeIndex,
params,
&compositeIndices)
}
// GetIndices returns all price indices
func (b *Bitmex) GetIndices() ([]Instrument, error) {
var indices []Instrument
return indices, b.SendHTTPRequest(bitmexEndpointIndices, nil, &indices)
}
// GetInsuranceFundHistory returns insurance fund history
func (b *Bitmex) GetInsuranceFundHistory(params GenericRequestParams) ([]Insurance, error) {
var history []Insurance
return history, b.SendHTTPRequest(bitmexEndpointIndices, params, &history)
}
// GetLeaderboard returns leaderboard information
func (b *Bitmex) GetLeaderboard(params LeaderboardGetParams) ([]Leaderboard, error) {
var leader []Leaderboard
return leader, b.SendHTTPRequest(bitmexEndpointLeader, params, &leader)
}
// GetAliasOnLeaderboard returns your alias on the leaderboard
func (b *Bitmex) GetAliasOnLeaderboard() (Alias, error) {
var alias Alias
return alias, b.SendHTTPRequest(bitmexEndpointAlias, nil, &alias)
}
// GetLiquidationOrders returns liquidation orders
func (b *Bitmex) GetLiquidationOrders(params GenericRequestParams) ([]Liquidation, error) {
var orders []Liquidation
return orders, b.SendHTTPRequest(bitmexEndpointLiquidation,
params,
&orders)
}
// GetCurrentNotifications returns your current notifications
func (b *Bitmex) GetCurrentNotifications() ([]Notification, error) {
var notifications []Notification
return notifications, b.SendAuthenticatedHTTPRequest("GET",
bitmexEndpointNotifications,
nil,
&notifications)
}
// GetOrders returns all the orders, open and closed
func (b *Bitmex) GetOrders(params GenericRequestParams) ([]Order, error) {
var orders []Order
return orders, b.SendAuthenticatedHTTPRequest("GET",
bitmexEndpointOrder,
params,
&orders)
}
// AmendOrder amends the quantity or price of an open order
func (b *Bitmex) AmendOrder(params OrderAmendParams) ([]Order, error) {
var orders []Order
return orders, b.SendAuthenticatedHTTPRequest("PUT",
bitmexEndpointOrder,
params,
&orders)
}
// CreateOrder creates a new order
func (b *Bitmex) CreateOrder(params OrderNewParams) (Order, error) {
var orderInfo Order
return orderInfo, b.SendAuthenticatedHTTPRequest("POST",
bitmexEndpointOrder,
params,
&orderInfo)
}
// CancelOrders cancels one or a batch of orders on the exchange and returns
// a cancelled order list
func (b *Bitmex) CancelOrders(params OrderCancelParams) ([]Order, error) {
var cancelledOrders []Order
return cancelledOrders, b.SendAuthenticatedHTTPRequest("DELETE",
bitmexEndpointOrder,
params,
&cancelledOrders)
}
// CancelAllOrders cancels all open orders on the exchange
func (b *Bitmex) CancelAllOrders(params OrderCancelAllParams) ([]Order, error) {
var cancelledOrders []Order
return cancelledOrders, b.SendAuthenticatedHTTPRequest("DELETE",
bitmexEndpointCancelAllOrders,
params,
&cancelledOrders)
}
// AmendBulkOrders amends multiple orders for the same symbol
func (b *Bitmex) AmendBulkOrders(params OrderAmendBulkParams) ([]Order, error) {
var amendedOrders []Order
return amendedOrders, b.SendAuthenticatedHTTPRequest("PUT",
bitmexEndpointBulk,
params,
&amendedOrders)
}
// CreateBulkOrders creates multiple orders for the same symbol
func (b *Bitmex) CreateBulkOrders(params OrderNewBulkParams) ([]Order, error) {
var orders []Order
return orders, b.SendAuthenticatedHTTPRequest("POST",
bitmexEndpointBulk,
params,
&orders)
}
// CancelAllOrdersAfterTime closes all positions after a certain time period
func (b *Bitmex) CancelAllOrdersAfterTime(params OrderCancelAllAfterParams) ([]Order, error) {
var cancelledOrder []Order
return cancelledOrder, b.SendAuthenticatedHTTPRequest("POST",
bitmexEndpointCancelOrderAfter,
params,
&cancelledOrder)
}
// ClosePosition closes a position WARNING deprecated use /order endpoint
func (b *Bitmex) ClosePosition(params OrderClosePositionParams) ([]Order, error) {
var closedPositions []Order
return closedPositions, b.SendAuthenticatedHTTPRequest("POST",
bitmexEndpointOrder,
params,
&closedPositions)
}
// GetOrderbook returns layer two orderbook data
func (b *Bitmex) GetOrderbook(params OrderBookGetL2Params) ([]OrderBookL2, error) {
var orderBooks []OrderBookL2
return orderBooks, b.SendHTTPRequest(bitmexEndpointOrderbookL2,
params,
&orderBooks)
}
// GetPositions returns positions
func (b *Bitmex) GetPositions(params PositionGetParams) ([]Position, error) {
var positions []Position
return positions, b.SendAuthenticatedHTTPRequest("GET",
bitmexEndpointPosition,
params,
&positions)
}
// IsolatePosition enables isolated margin or cross margin per-position
func (b *Bitmex) IsolatePosition(params PositionIsolateMarginParams) (Position, error) {
var position Position
return position, b.SendAuthenticatedHTTPRequest("POST",
bitmexEndpointIsolatePosition,
params,
&position)
}
// LeveragePosition chooses leverage for a position
func (b *Bitmex) LeveragePosition(params PositionUpdateLeverageParams) (Position, error) {
var position Position
return position, b.SendAuthenticatedHTTPRequest("POST",
bitmexEndpointLeveragePosition,
params,
&position)
}
// UpdateRiskLimit updates risk limit on a position
func (b *Bitmex) UpdateRiskLimit(params PositionUpdateRiskLimitParams) (Position, error) {
var position Position
return position, b.SendAuthenticatedHTTPRequest("POST",
bitmexEndpointAdjustRiskLimit,
params,
&position)
}
// TransferMargin transfers equity in or out of a position
func (b *Bitmex) TransferMargin(params PositionTransferIsolatedMarginParams) (Position, error) {
var position Position
return position, b.SendAuthenticatedHTTPRequest("POST",
bitmexEndpointTransferMargin,
params,
&position)
}
// GetQuotes returns quotations
func (b *Bitmex) GetQuotes(params GenericRequestParams) ([]Quote, error) {
var quotations []Quote
return quotations, b.SendHTTPRequest(bitmexEndpointQuote,
params,
&quotations)
}
// GetQuotesByBuckets returns previous quotes in time buckets
func (b *Bitmex) GetQuotesByBuckets(params QuoteGetBucketedParams) ([]Quote, error) {
var quotations []Quote
return quotations, b.SendHTTPRequest(bitmexEndpointQuoteBucketed,
params,
&quotations)
}
// GetSettlementHistory returns settlement history
func (b *Bitmex) GetSettlementHistory(params GenericRequestParams) ([]Settlement, error) {
var history []Settlement
return history, b.SendHTTPRequest(bitmexEndpointSettlement,
params,
&history)
}
// GetStats returns exchange wide per series turnover and volume statistics
func (b *Bitmex) GetStats() ([]Stats, error) {
var stats []Stats
return stats, b.SendHTTPRequest(bitmexEndpointStats, nil, &stats)
}
// GetStatsHistorical historic stats
func (b *Bitmex) GetStatsHistorical() ([]StatsHistory, error) {
var history []StatsHistory
return history, b.SendHTTPRequest(bitmexEndpointStatsHistory, nil, &history)
}
// GetStatSummary returns the stats summary in USD terms
func (b *Bitmex) GetStatSummary() ([]StatsUSD, error) {
var summary []StatsUSD
return summary, b.SendHTTPRequest(bitmexEndpointStatsSummary, nil, &summary)
}
// GetTrade returns executed trades on the desk
func (b *Bitmex) GetTrade(params GenericRequestParams) ([]Trade, error) {
var trade []Trade
return trade, b.SendHTTPRequest(bitmexEndpointTrade, params, &trade)
}
// GetPreviousTrades previous trade history in time buckets
func (b *Bitmex) GetPreviousTrades(params TradeGetBucketedParams) ([]Trade, error) {
var trade []Trade
return trade, b.SendHTTPRequest(bitmexEndpointTradeBucketed,
params,
&trade)
}
// GetUserInfo returns your user information
func (b *Bitmex) GetUserInfo() (User, error) {
var userInfo User
return userInfo, b.SendAuthenticatedHTTPRequest("GET",
bitmexEndpointUser,
nil,
&userInfo)
}
// UpdateUserInfo updates user information
func (b *Bitmex) UpdateUserInfo(params UserUpdateParams) (User, error) {
var userInfo User
return userInfo, b.SendAuthenticatedHTTPRequest("PUT",
bitmexEndpointUser,
params,
&userInfo)
}
// GetAffiliateStatus returns your affiliate status
func (b *Bitmex) GetAffiliateStatus() (AffiliateStatus, error) {
var status AffiliateStatus
return status, b.SendAuthenticatedHTTPRequest("GET",
bitmexEndpointUserAffiliate,
nil,
&status)
}
// CancelWithdraw cancels a current withdrawal
func (b *Bitmex) CancelWithdraw(token string) (TransactionInfo, error) {
var info TransactionInfo
return info, b.SendAuthenticatedHTTPRequest("POST",
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(referralCode string) (float64, error) {
var percentage float64
return percentage, b.SendHTTPRequest(bitmexEndpointUserCheckReferralCode,
UserCheckReferralCodeParams{ReferralCode: referralCode},
&percentage)
}
// GetUserCommision returns your account's commission status.
func (b *Bitmex) GetUserCommision(token string) (UserCommission, error) {
var commissionInfo UserCommission
return commissionInfo, b.SendAuthenticatedHTTPRequest("GET",
bitmexEndpointUserCommision,
nil,
&commissionInfo)
}
// ConfirmEmail confirms email address with a token
func (b *Bitmex) ConfirmEmail(token string) (ConfirmEmail, error) {
var confirmation ConfirmEmail
return confirmation, b.SendAuthenticatedHTTPRequest("GET",
bitmexEndpointUserConfirmEmail,
UserTokenParams{Token: token},
&confirmation)
}
// ConfirmTwoFactorAuth confirmas 2FA for this account.
func (b *Bitmex) ConfirmTwoFactorAuth(token, typ string) (bool, error) {
var working bool
return working, b.SendAuthenticatedHTTPRequest("POST",
bitmexEndpointUserConfirmTFA,
UserConfirmTFAParams{Token: token, Type: typ},
&working)
}
// ConfirmWithdrawal confirmas a withdrawal
func (b *Bitmex) ConfirmWithdrawal(token string) (TransactionInfo, error) {
var info TransactionInfo
return info, b.SendAuthenticatedHTTPRequest("POST",
bitmexEndpointUserCancelWithdraw,
UserTokenParams{Token: token},
&info)
}
// GetDepositAddress returns a deposit address for a cryptocurency
func (b *Bitmex) GetDepositAddress(currency string) (string, error) {
var address string
return address, b.SendAuthenticatedHTTPRequest("GET",
bitmexEndpointUserDepositAddress,
UserCurrencyParams{Currency: currency},
&address)
}
// DisableTFA dsiables 2 factor authentication for your account
func (b *Bitmex) DisableTFA(token, typ string) (bool, error) {
var disabled bool
return disabled, b.SendAuthenticatedHTTPRequest("POST",
bitmexEndpointUserDisableTFA,
UserConfirmTFAParams{Token: token, Type: typ},
&disabled)
}
// UserLogOut logs you out of BitMEX
func (b *Bitmex) UserLogOut() error {
return b.SendAuthenticatedHTTPRequest("POST",
bitmexEndpointUserLogout,
nil,
nil)
}
// UserLogOutAll logs you out of all systems for BitMEX
func (b *Bitmex) UserLogOutAll() (int64, error) {
var status int64
return status, b.SendAuthenticatedHTTPRequest("POST",
bitmexEndpointUserLogoutAll,
nil,
&status)
}
// GetUserMargin returns user margin information
func (b *Bitmex) GetUserMargin(currency string) (UserMargin, error) {
var info UserMargin
return info, b.SendAuthenticatedHTTPRequest("GET",
bitmexEndpointUserMargin,
UserCurrencyParams{Currency: currency},
&info)
}
// GetMinimumWithdrawalFee returns minimum withdrawal fee information
func (b *Bitmex) GetMinimumWithdrawalFee(currency string) (MinWithdrawalFee, error) {
var fee MinWithdrawalFee
return fee, b.SendAuthenticatedHTTPRequest("GET",
bitmexEndpointUserMinWithdrawalFee,
UserCurrencyParams{Currency: currency},
&fee)
}
// GetUserPreferences returns user preferences
func (b *Bitmex) GetUserPreferences(params UserPreferencesParams) (User, error) {
var userInfo User
return userInfo, b.SendAuthenticatedHTTPRequest("POST",
bitmexEndpointUserPreferences,
params,
&userInfo)
}
// EnableTFA enables 2 factor authentication
func (b *Bitmex) EnableTFA(typ string) (bool, error) {
var enabled bool
return enabled, b.SendAuthenticatedHTTPRequest("POST",
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(params UserRequestWithdrawalParams) (TransactionInfo, error) {
var info TransactionInfo
return info, b.SendAuthenticatedHTTPRequest("POST",
bitmexEndpointUserRequestWithdraw,
params,
&info)
}
// GetWalletInfo returns user wallet information
func (b *Bitmex) GetWalletInfo(currency string) (WalletInfo, error) {
var info WalletInfo
return info, b.SendAuthenticatedHTTPRequest("GET",
bitmexEndpointUserWallet,
UserCurrencyParams{Currency: currency},
&info)
}
// GetWalletHistory returns user wallet history transaction data
func (b *Bitmex) GetWalletHistory(currency string) ([]TransactionInfo, error) {
var info []TransactionInfo
return info, b.SendAuthenticatedHTTPRequest("GET",
bitmexEndpointUserWalletHistory,
UserCurrencyParams{Currency: currency},
&info)
}
// GetWalletSummary returns user wallet summary
func (b *Bitmex) GetWalletSummary(currency string) ([]TransactionInfo, error) {
var info []TransactionInfo
return info, b.SendAuthenticatedHTTPRequest("GET",
bitmexEndpointUserWalletSummary,
UserCurrencyParams{Currency: currency},
&info)
}
// SendHTTPRequest sends an unauthenticated HTTP request
func (b *Bitmex) SendHTTPRequest(path string, params Parameter, result interface{}) error {
var respCheck interface{}
path = bitmexAPIURL + path
if params != nil {
if !params.IsNil() {
encodedPath, err := params.ToURLVals(path)
if err != nil {
return err
}
err = b.SendPayload("GET", encodedPath, nil, nil, &respCheck, false, b.Verbose)
if err != nil {
return err
}
return b.CaptureError(respCheck, result)
}
}
err := b.SendPayload("GET", path, nil, nil, &respCheck, false, b.Verbose)
if err != nil {
return err
}
return b.CaptureError(respCheck, result)
}
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request to bitmex
func (b *Bitmex) SendAuthenticatedHTTPRequest(verb, path string, params Parameter, result interface{}) error {
if !b.AuthenticatedAPISupport {
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet,
b.Name)
}
timestamp := time.Now().Add(time.Second * 10).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.APIKey
var payload string
if params != nil {
err := params.VerifyData()
if err != nil {
return err
}
data, err := common.JSONEncode(params)
if err != nil {
return err
}
payload = string(data)
}
hmac := common.GetHMAC(common.HashSHA256,
[]byte(verb+"/api/v1"+path+timestampNew+payload),
[]byte(b.APISecret))
headers["api-signature"] = common.HexEncodeToString(hmac)
var respCheck interface{}
err := b.SendPayload(verb,
bitmexAPIURL+path,
headers,
bytes.NewBuffer([]byte(payload)),
&respCheck,
true,
b.Verbose)
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 = common.JSONDecode(marshalled, &Error)
if err == nil {
return fmt.Errorf("bitmex error %s: %s",
Error.Error.Name,
Error.Error.Message)
}
err = common.JSONDecode(marshalled, reType)
if err != nil {
return err
}
return nil
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,365 @@
package bitmex
import (
"sync"
"testing"
"time"
"github.com/thrasher-/gocryptotrader/config"
)
// Please supply your own keys here for due diligence testing
const (
testAPIKey = ""
testAPISecret = ""
)
var b Bitmex
func TestSetDefaults(t *testing.T) {
b.SetDefaults()
}
func TestSetup(t *testing.T) {
cfg := config.GetConfig()
cfg.LoadConfig("../../testdata/configtest.json")
bitmexConfig, err := cfg.GetExchangeConfig("Bitmex")
if err != nil {
t.Error("Test Failed - Bitmex Setup() init error")
}
bitmexConfig.AuthenticatedAPISupport = true
bitmexConfig.APIKey = testAPIKey
bitmexConfig.APISecret = testAPISecret
b.Setup(bitmexConfig)
}
func TestStart(t *testing.T) {
var testWg sync.WaitGroup
b.Start(&testWg)
testWg.Wait()
}
func TestGetUrgentAnnouncement(t *testing.T) {
_, err := b.GetUrgentAnnouncement()
if err == nil {
t.Error("test failed - GetUrgentAnnouncement() error", err)
}
}
func TestGetAPIKeys(t *testing.T) {
_, err := b.GetAPIKeys()
if err == nil {
t.Error("test failed - GetAPIKeys() error", err)
}
}
func TestRemoveAPIKey(t *testing.T) {
_, err := b.RemoveAPIKey(APIKeyParams{APIKeyID: "1337"})
if err == nil {
t.Error("test failed - RemoveAPIKey() error", err)
}
}
func TestDisableAPIKey(t *testing.T) {
_, err := b.DisableAPIKey(APIKeyParams{APIKeyID: "1337"})
if err == nil {
t.Error("test failed - DisableAPIKey() error", err)
}
}
func TestEnableAPIKey(t *testing.T) {
_, err := b.EnableAPIKey(APIKeyParams{APIKeyID: "1337"})
if err == nil {
t.Error("test failed - EnableAPIKey() error", err)
}
}
func TestGetTrollboxMessages(t *testing.T) {
_, err := b.GetTrollboxMessages(ChatGetParams{Count: 5})
if err != nil {
t.Error("test failed - GetTrollboxMessages() error", err)
}
}
func TestSendTrollboxMessage(t *testing.T) {
_, err := b.SendTrollboxMessage(ChatSendParams{
ChannelID: 1337,
Message: "Hello,World!"})
if err == nil {
t.Error("test failed - SendTrollboxMessage() error", err)
}
}
func TestGetTrollboxChannels(t *testing.T) {
_, err := b.GetTrollboxChannels()
if err != nil {
t.Error("test failed - GetTrollboxChannels() error", err)
}
}
func TestGetTrollboxConnectedUsers(t *testing.T) {
_, err := b.GetTrollboxConnectedUsers()
if err == nil {
t.Error("test failed - GetTrollboxConnectedUsers() error", err)
}
}
func TestGetAccountExecutions(t *testing.T) {
_, err := b.GetAccountExecutions(GenericRequestParams{})
if err == nil {
t.Error("test failed - GetAccountExecutions() error", err)
}
}
func TestGetAccountExecutionTradeHistory(t *testing.T) {
_, err := b.GetAccountExecutionTradeHistory(GenericRequestParams{})
if err == nil {
t.Error("test failed - GetAccountExecutionTradeHistory() error", err)
}
}
func TestGetFundingHistory(t *testing.T) {
_, err := b.GetFundingHistory()
if err != nil {
t.Error("test failed - GetFundingHistory() error", err)
}
}
func TestGetInstruments(t *testing.T) {
_, err := b.GetInstruments(GenericRequestParams{})
if err != nil {
t.Error("test failed - GetInstruments() error", err)
}
}
func TestGetActiveInstruments(t *testing.T) {
_, err := b.GetActiveInstruments(GenericRequestParams{})
if err != nil {
t.Error("test failed - GetActiveInstruments() error", err)
}
}
func TestGetActiveAndIndexInstruments(t *testing.T) {
_, err := b.GetActiveAndIndexInstruments()
if err != nil {
t.Error("test failed - GetActiveAndIndexInstruments() error", err)
}
}
func TestGetActiveIntervals(t *testing.T) {
_, err := b.GetActiveIntervals()
if err == nil {
t.Error("test failed - GetActiveIntervals() error", err)
}
}
func TestGetCompositeIndex(t *testing.T) {
_, err := b.GetCompositeIndex(GenericRequestParams{})
if err == nil {
t.Error("test failed - GetCompositeIndex() error", err)
}
}
func TestGetIndices(t *testing.T) {
_, err := b.GetIndices()
if err != nil {
t.Error("test failed - GetIndices() error", err)
}
}
func TestGetInsuranceFundHistory(t *testing.T) {
_, err := b.GetInsuranceFundHistory(GenericRequestParams{})
if err != nil {
t.Error("test failed - GetInsuranceFundHistory() error", err)
}
}
func TestGetLeaderboard(t *testing.T) {
_, err := b.GetLeaderboard(LeaderboardGetParams{})
if err != nil {
t.Error("test failed - GetLeaderboard() error", err)
}
}
func TestGetAliasOnLeaderboard(t *testing.T) {
_, err := b.GetAliasOnLeaderboard()
if err == nil {
t.Error("test failed - GetAliasOnLeaderboard() error", err)
}
}
func TestGetLiquidationOrders(t *testing.T) {
_, err := b.GetLiquidationOrders(GenericRequestParams{})
if err != nil {
t.Error("test failed - GetLiquidationOrders() error", err)
}
}
func TestGetCurrentNotifications(t *testing.T) {
_, err := b.GetCurrentNotifications()
if err == nil {
t.Error("test failed - GetCurrentNotifications() error", err)
}
}
func TestGetOrders(t *testing.T) {
_, err := b.GetOrders(GenericRequestParams{})
if err == nil {
t.Error("test failed - GetOrders() error", err)
}
}
func TestAmendOrder(t *testing.T) {
_, err := b.AmendOrder(OrderAmendParams{})
if err == nil {
t.Error("test failed - AmendOrder() error", err)
}
}
func TestCreateOrder(t *testing.T) {
_, err := b.CreateOrder(OrderNewParams{Symbol: "XBTM15",
Price: 219.0,
ClOrdID: "mm_bitmex_1a/oemUeQ4CAJZgP3fjHsA",
OrderQty: 98})
if err == nil {
t.Error("test failed - CreateOrder() error", err)
}
}
func TestCancelOrders(t *testing.T) {
_, err := b.CancelOrders(OrderCancelParams{})
if err == nil {
t.Error("test failed - CancelOrders() error", err)
}
}
func TestCancelAllOrders(t *testing.T) {
_, err := b.CancelAllOrders(OrderCancelAllParams{})
if err == nil {
t.Error("test failed - CancelAllOrders() error", err)
}
}
func TestAmendBulkOrders(t *testing.T) {
_, err := b.AmendBulkOrders(OrderAmendBulkParams{})
if err == nil {
t.Error("test failed - AmendBulkOrders() error", err)
}
}
func TestCreateBulkOrders(t *testing.T) {
_, err := b.CreateBulkOrders(OrderNewBulkParams{})
if err == nil {
t.Error("test failed - CreateBulkOrders() error", err)
}
}
func TestCancelAllOrdersAfterTime(t *testing.T) {
_, err := b.CancelAllOrdersAfterTime(OrderCancelAllAfterParams{})
if err == nil {
t.Error("test failed - CancelAllOrdersAfterTime() error", err)
}
}
func TestClosePosition(t *testing.T) {
_, err := b.ClosePosition(OrderClosePositionParams{})
if err == nil {
t.Error("test failed - ClosePosition() error", err)
}
}
func TestGetOrderbook(t *testing.T) {
_, err := b.GetOrderbook(OrderBookGetL2Params{Symbol: "XBT"})
if err != nil {
t.Error("test failed - GetOrderbook() error", err)
}
}
func TestGetPositions(t *testing.T) {
_, err := b.GetPositions(PositionGetParams{})
if err == nil {
t.Error("test failed - GetPositions() error", err)
}
}
func TestIsolatePosition(t *testing.T) {
_, err := b.IsolatePosition(PositionIsolateMarginParams{Symbol: "XBT"})
if err == nil {
t.Error("test failed - IsolatePosition() error", err)
}
}
func TestLeveragePosition(t *testing.T) {
_, err := b.LeveragePosition(PositionUpdateLeverageParams{})
if err == nil {
t.Error("test failed - LeveragePosition() error", err)
}
}
func TestUpdateRiskLimit(t *testing.T) {
_, err := b.UpdateRiskLimit(PositionUpdateRiskLimitParams{})
if err == nil {
t.Error("test failed - UpdateRiskLimit() error", err)
}
}
func TestTransferMargin(t *testing.T) {
_, err := b.TransferMargin(PositionTransferIsolatedMarginParams{})
if err == nil {
t.Error("test failed - TransferMargin() error", err)
}
}
func TestGetQuotesByBuckets(t *testing.T) {
_, err := b.GetQuotesByBuckets(QuoteGetBucketedParams{})
if err == nil {
t.Error("test failed - GetQuotesByBuckets() error", err)
}
}
func TestGetSettlementHistory(t *testing.T) {
_, err := b.GetSettlementHistory(GenericRequestParams{})
if err != nil {
t.Error("test failed - GetSettlementHistory() error", err)
}
}
func TestGetStats(t *testing.T) {
_, err := b.GetStats()
if err != nil {
t.Error("test failed - GetStats() error", err)
}
}
func TestGetStatsHistorical(t *testing.T) {
_, err := b.GetStatsHistorical()
if err != nil {
t.Error("test failed - GetStatsHistorical() error", err)
}
}
func TestGetStatSummary(t *testing.T) {
_, err := b.GetStatSummary()
if err != nil {
t.Error("test failed - GetStatSummary() error", err)
}
}
func TestGetTrade(t *testing.T) {
_, err := b.GetTrade(GenericRequestParams{
Symbol: "XBTUSD",
StartTime: time.Now().Format(time.RFC3339),
Reverse: true})
if err != nil {
t.Error("test failed - GetTrade() error", err)
}
}
func TestGetPreviousTrades(t *testing.T) {
_, err := b.GetPreviousTrades(TradeGetBucketedParams{})
if err == nil {
t.Error("test failed - GetPreviousTrades() error", err)
}
}

View File

@@ -0,0 +1,668 @@
package bitmex
// RequestError allows for a general error capture from requests
type RequestError struct {
Error struct {
Message string `json:"message"`
Name string `json:"name"`
} `json:"error"`
}
// Announcement General Announcements
type Announcement struct {
Content string `json:"content"`
Date string `json:"date"`
ID int32 `json:"id"`
Link string `json:"link"`
Title string `json:"title"`
}
// APIKey Persistent API Keys for Developers
type APIKey struct {
Cidr string `json:"cidr"`
Created string `json:"created"`
Enabled bool `json:"enabled"`
ID string `json:"id"`
Name string `json:"name"`
Nonce int64 `json:"nonce"`
Permissions []interface{} `json:"permissions"`
Secret string `json:"secret"`
UserID int32 `json:"userId"`
}
// Chat Trollbox Data
type Chat struct {
ChannelID float64 `json:"channelID"`
Date string `json:"date"`
FromBot bool `json:"fromBot"`
HTML string `json:"html"`
ID int32 `json:"id"`
Message string `json:"message"`
User string `json:"user"`
}
// ChatChannel chat channel
type ChatChannel struct {
ID int32 `json:"id"`
Name string `json:"name"`
}
// ConnectedUsers connected users
type ConnectedUsers struct {
Bots int32 `json:"bots"`
Users int32 `json:"users"`
}
// Execution Raw Order and Balance Data
type Execution struct {
Account int64 `json:"account"`
AvgPx float64 `json:"avgPx"`
ClOrdID string `json:"clOrdID"`
ClOrdLinkID string `json:"clOrdLinkID"`
Commission float64 `json:"commission"`
ContingencyType string `json:"contingencyType"`
CumQty int64 `json:"cumQty"`
Currency string `json:"currency"`
DisplayQty int64 `json:"displayQty"`
ExDestination string `json:"exDestination"`
ExecComm int64 `json:"execComm"`
ExecCost int64 `json:"execCost"`
ExecID string `json:"execID"`
ExecInst string `json:"execInst"`
ExecType string `json:"execType"`
ForeignNotional float64 `json:"foreignNotional"`
HomeNotional float64 `json:"homeNotional"`
LastLiquidityInd string `json:"lastLiquidityInd"`
LastMkt string `json:"lastMkt"`
LastPx float64 `json:"lastPx"`
LastQty int64 `json:"lastQty"`
LeavesQty int64 `json:"leavesQty"`
MultiLegReportingType string `json:"multiLegReportingType"`
OrdRejReason string `json:"ordRejReason"`
OrdStatus string `json:"ordStatus"`
OrdType string `json:"ordType"`
OrderID string `json:"orderID"`
OrderQty int64 `json:"orderQty"`
PegOffsetValue float64 `json:"pegOffsetValue"`
PegPriceType string `json:"pegPriceType"`
Price float64 `json:"price"`
SettlCurrency string `json:"settlCurrency"`
Side string `json:"side"`
SimpleCumQty float64 `json:"simpleCumQty"`
SimpleLeavesQty float64 `json:"simpleLeavesQty"`
SimpleOrderQty float64 `json:"simpleOrderQty"`
StopPx float64 `json:"stopPx"`
Symbol string `json:"symbol"`
Text string `json:"text"`
TimeInForce string `json:"timeInForce"`
Timestamp string `json:"timestamp"`
TradePublishIndicator string `json:"tradePublishIndicator"`
TransactTime string `json:"transactTime"`
TrdMatchID string `json:"trdMatchID"`
Triggered string `json:"triggered"`
UnderlyingLastPx float64 `json:"underlyingLastPx"`
WorkingIndicator bool `json:"workingIndicator"`
}
// Funding Swap Funding History
type Funding struct {
FundingInterval string `json:"fundingInterval"`
FundingRate float64 `json:"fundingRate"`
FundingRateDaily float64 `json:"fundingRateDaily"`
Symbol string `json:"symbol"`
Timestamp string `json:"timestamp"`
}
// Instrument Tradeable Contracts, Indices, and History
type Instrument struct {
AskPrice float64 `json:"askPrice"`
BankruptLimitDownPrice float64 `json:"bankruptLimitDownPrice"`
BankruptLimitUpPrice float64 `json:"bankruptLimitUpPrice"`
BidPrice float64 `json:"bidPrice"`
BuyLeg string `json:"buyLeg"`
CalcInterval string `json:"calcInterval"`
Capped bool `json:"capped"`
ClosingTimestamp string `json:"closingTimestamp"`
Deleverage bool `json:"deleverage"`
Expiry string `json:"expiry"`
FairBasis float64 `json:"fairBasis"`
FairBasisRate float64 `json:"fairBasisRate"`
FairMethod string `json:"fairMethod"`
FairPrice float64 `json:"fairPrice"`
Front string `json:"front"`
FundingBaseSymbol string `json:"fundingBaseSymbol"`
FundingInterval string `json:"fundingInterval"`
FundingPremiumSymbol string `json:"fundingPremiumSymbol"`
FundingQuoteSymbol string `json:"fundingQuoteSymbol"`
FundingRate float64 `json:"fundingRate"`
FundingTimestamp string `json:"fundingTimestamp"`
HasLiquidity bool `json:"hasLiquidity"`
HighPrice float64 `json:"highPrice"`
ImpactAskPrice float64 `json:"impactAskPrice"`
ImpactBidPrice float64 `json:"impactBidPrice"`
ImpactMidPrice float64 `json:"impactMidPrice"`
IndicativeFundingRate float64 `json:"indicativeFundingRate"`
IndicativeSettlePrice float64 `json:"indicativeSettlePrice"`
IndicativeTaxRate float64 `json:"indicativeTaxRate"`
InitMargin float64 `json:"initMargin"`
InsuranceFee float64 `json:"insuranceFee"`
InverseLeg string `json:"inverseLeg"`
IsInverse bool `json:"isInverse"`
IsQuanto bool `json:"isQuanto"`
LastChangePcnt float64 `json:"lastChangePcnt"`
LastPrice float64 `json:"lastPrice"`
LastPriceProtected float64 `json:"lastPriceProtected"`
LastTickDirection string `json:"lastTickDirection"`
Limit float64 `json:"limit"`
LimitDownPrice float64 `json:"limitDownPrice"`
LimitUpPrice float64 `json:"limitUpPrice"`
Listing string `json:"listing"`
LotSize int64 `json:"lotSize"`
LowPrice float64 `json:"lowPrice"`
MaintMargin float64 `json:"maintMargin"`
MakerFee float64 `json:"makerFee"`
MarkMethod string `json:"markMethod"`
MarkPrice float64 `json:"markPrice"`
MaxOrderQty int64 `json:"maxOrderQty"`
MaxPrice float64 `json:"maxPrice"`
MidPrice float64 `json:"midPrice"`
Multiplier int64 `json:"multiplier"`
OpenInterest int64 `json:"openInterest"`
OpenValue int64 `json:"openValue"`
OpeningTimestamp string `json:"openingTimestamp"`
OptionMultiplier float64 `json:"optionMultiplier"`
OptionStrikePcnt float64 `json:"optionStrikePcnt"`
OptionStrikePrice float64 `json:"optionStrikePrice"`
OptionStrikeRound float64 `json:"optionStrikeRound"`
OptionUnderlyingPrice float64 `json:"optionUnderlyingPrice"`
PositionCurrency string `json:"positionCurrency"`
PrevClosePrice float64 `json:"prevClosePrice"`
PrevPrice24h float64 `json:"prevPrice24h"`
PrevTotalTurnover int64 `json:"prevTotalTurnover"`
PrevTotalVolume int64 `json:"prevTotalVolume"`
PublishInterval string `json:"publishInterval"`
PublishTime string `json:"publishTime"`
QuoteCurrency string `json:"quoteCurrency"`
QuoteToSettleMultiplier int64 `json:"quoteToSettleMultiplier"`
RebalanceInterval string `json:"rebalanceInterval"`
RebalanceTimestamp string `json:"rebalanceTimestamp"`
Reference string `json:"reference"`
ReferenceSymbol string `json:"referenceSymbol"`
RelistInterval string `json:"relistInterval"`
RiskLimit int64 `json:"riskLimit"`
RiskStep int64 `json:"riskStep"`
RootSymbol string `json:"rootSymbol"`
SellLeg string `json:"sellLeg"`
SessionInterval string `json:"sessionInterval"`
SettlCurrency string `json:"settlCurrency"`
Settle string `json:"settle"`
SettledPrice float64 `json:"settledPrice"`
SettlementFee float64 `json:"settlementFee"`
State string `json:"state"`
Symbol string `json:"symbol"`
TakerFee float64 `json:"takerFee"`
Taxed bool `json:"taxed"`
TickSize float64 `json:"tickSize"`
Timestamp string `json:"timestamp"`
TotalTurnover int64 `json:"totalTurnover"`
TotalVolume int64 `json:"totalVolume"`
Turnover int64 `json:"turnover"`
Turnover24h int64 `json:"turnover24h"`
Typ string `json:"typ"`
Underlying string `json:"underlying"`
UnderlyingSymbol string `json:"underlyingSymbol"`
UnderlyingToPositionMultiplier int64 `json:"underlyingToPositionMultiplier"`
UnderlyingToSettleMultiplier int64 `json:"underlyingToSettleMultiplier"`
Volume int64 `json:"volume"`
Volume24h int64 `json:"volume24h"`
Vwap float64 `json:"vwap"`
}
// InstrumentInterval instrument interval
type InstrumentInterval struct {
Intervals []string `json:"intervals"`
Symbols []string `json:"symbols"`
}
// IndexComposite index composite
type IndexComposite struct {
IndexSymbol string `json:"indexSymbol"`
LastPrice float64 `json:"lastPrice"`
Logged string `json:"logged"`
Reference string `json:"reference"`
Symbol string `json:"symbol"`
Timestamp string `json:"timestamp"`
Weight float64 `json:"weight"`
}
// Insurance Insurance Fund Data
type Insurance struct {
Currency string `json:"currency"`
Timestamp string `json:"timestamp"`
WalletBalance int64 `json:"walletBalance"`
}
// Leaderboard Information on Top Users
type Leaderboard struct {
IsRealName bool `json:"isRealName"`
Name string `json:"name"`
Profit float64 `json:"profit"`
}
// Alias Name refers to Trollbox client name
type Alias struct {
Name string `json:"name"`
}
// Liquidation Active Liquidations
type Liquidation struct {
LeavesQty int64 `json:"leavesQty"`
OrderID string `json:"orderID"`
Price float64 `json:"price"`
Side string `json:"side"`
Symbol string `json:"symbol"`
}
// Notification Account Notifications
type Notification struct {
Body string `json:"body"`
Closable bool `json:"closable"`
Date string `json:"date"`
ID int32 `json:"id"`
Persist bool `json:"persist"`
Sound string `json:"sound"`
Title string `json:"title"`
TTL int32 `json:"ttl"`
Type string `json:"type"`
WaitForVisibility bool `json:"waitForVisibility"`
}
// Order Placement, Cancellation, Amending, and History
type Order struct {
Account int64 `json:"account"`
AvgPx float64 `json:"avgPx"`
ClOrdID string `json:"clOrdID"`
ClOrdLinkID string `json:"clOrdLinkID"`
ContingencyType string `json:"contingencyType"`
CumQty int64 `json:"cumQty"`
Currency string `json:"currency"`
DisplayQty int64 `json:"displayQty"`
ExDestination string `json:"exDestination"`
ExecInst string `json:"execInst"`
LeavesQty int64 `json:"leavesQty"`
MultiLegReportingType string `json:"multiLegReportingType"`
OrdRejReason string `json:"ordRejReason"`
OrdStatus string `json:"ordStatus"`
OrdType string `json:"ordType"`
OrderID string `json:"orderID"`
OrderQty int64 `json:"orderQty"`
PegOffsetValue float64 `json:"pegOffsetValue"`
PegPriceType string `json:"pegPriceType"`
Price float64 `json:"price"`
SettlCurrency string `json:"settlCurrency"`
Side string `json:"side"`
SimpleCumQty float64 `json:"simpleCumQty"`
SimpleLeavesQty float64 `json:"simpleLeavesQty"`
SimpleOrderQty float64 `json:"simpleOrderQty"`
StopPx float64 `json:"stopPx"`
Symbol string `json:"symbol"`
Text string `json:"text"`
TimeInForce string `json:"timeInForce"`
Timestamp string `json:"timestamp"`
TransactTime string `json:"transactTime"`
Triggered string `json:"triggered"`
WorkingIndicator bool `json:"workingIndicator"`
}
// OrderBookL2 contains order book l2
type OrderBookL2 struct {
ID int64 `json:"id"`
Price float64 `json:"price"`
Side string `json:"side"`
Size int64 `json:"size"`
Symbol string `json:"symbol"`
}
// Position Summary of Open and Closed Positions
type Position struct {
Account int64 `json:"account"`
AvgCostPrice float64 `json:"avgCostPrice"`
AvgEntryPrice float64 `json:"avgEntryPrice"`
BankruptPrice float64 `json:"bankruptPrice"`
BreakEvenPrice float64 `json:"breakEvenPrice"`
Commission float64 `json:"commission"`
CrossMargin bool `json:"crossMargin"`
Currency string `json:"currency"`
CurrentComm int64 `json:"currentComm"`
CurrentCost int64 `json:"currentCost"`
CurrentQty int64 `json:"currentQty"`
CurrentTimestamp string `json:"currentTimestamp"`
DeleveragePercentile float64 `json:"deleveragePercentile"`
ExecBuyCost int64 `json:"execBuyCost"`
ExecBuyQty int64 `json:"execBuyQty"`
ExecComm int64 `json:"execComm"`
ExecCost int64 `json:"execCost"`
ExecQty int64 `json:"execQty"`
ExecSellCost int64 `json:"execSellCost"`
ExecSellQty int64 `json:"execSellQty"`
ForeignNotional float64 `json:"foreignNotional"`
GrossExecCost int64 `json:"grossExecCost"`
GrossOpenCost int64 `json:"grossOpenCost"`
GrossOpenPremium int64 `json:"grossOpenPremium"`
HomeNotional float64 `json:"homeNotional"`
IndicativeTax int64 `json:"indicativeTax"`
IndicativeTaxRate float64 `json:"indicativeTaxRate"`
InitMargin int64 `json:"initMargin"`
InitMarginReq float64 `json:"initMarginReq"`
IsOpen bool `json:"isOpen"`
LastPrice float64 `json:"lastPrice"`
LastValue int64 `json:"lastValue"`
Leverage float64 `json:"leverage"`
LiquidationPrice float64 `json:"liquidationPrice"`
LongBankrupt int64 `json:"longBankrupt"`
MaintMargin int64 `json:"maintMargin"`
MaintMarginReq float64 `json:"maintMarginReq"`
MarginCallPrice float64 `json:"marginCallPrice"`
MarkPrice float64 `json:"markPrice"`
MarkValue int64 `json:"markValue"`
OpenOrderBuyCost int64 `json:"openOrderBuyCost"`
OpenOrderBuyPremium int64 `json:"openOrderBuyPremium"`
OpenOrderBuyQty int64 `json:"openOrderBuyQty"`
OpenOrderSellCost int64 `json:"openOrderSellCost"`
OpenOrderSellPremium int64 `json:"openOrderSellPremium"`
OpenOrderSellQty int64 `json:"openOrderSellQty"`
OpeningComm int64 `json:"openingComm"`
OpeningCost int64 `json:"openingCost"`
OpeningQty int64 `json:"openingQty"`
OpeningTimestamp string `json:"openingTimestamp"`
PosAllowance int64 `json:"posAllowance"`
PosComm int64 `json:"posComm"`
PosCost int64 `json:"posCost"`
PosCost2 int64 `json:"posCost2"`
PosCross int64 `json:"posCross"`
PosInit int64 `json:"posInit"`
PosLoss int64 `json:"posLoss"`
PosMaint int64 `json:"posMaint"`
PosMargin int64 `json:"posMargin"`
PosState string `json:"posState"`
PrevClosePrice float64 `json:"prevClosePrice"`
PrevRealisedPnl int64 `json:"prevRealisedPnl"`
PrevUnrealisedPnl int64 `json:"prevUnrealisedPnl"`
QuoteCurrency string `json:"quoteCurrency"`
RealisedCost int64 `json:"realisedCost"`
RealisedGrossPnl int64 `json:"realisedGrossPnl"`
RealisedPnl int64 `json:"realisedPnl"`
RealisedTax int64 `json:"realisedTax"`
RebalancedPnl int64 `json:"rebalancedPnl"`
RiskLimit int64 `json:"riskLimit"`
RiskValue int64 `json:"riskValue"`
SessionMargin int64 `json:"sessionMargin"`
ShortBankrupt int64 `json:"shortBankrupt"`
SimpleCost float64 `json:"simpleCost"`
SimplePnl float64 `json:"simplePnl"`
SimplePnlPcnt float64 `json:"simplePnlPcnt"`
SimpleQty float64 `json:"simpleQty"`
SimpleValue float64 `json:"simpleValue"`
Symbol string `json:"symbol"`
TargetExcessMargin int64 `json:"targetExcessMargin"`
TaxBase int64 `json:"taxBase"`
TaxableMargin int64 `json:"taxableMargin"`
Timestamp string `json:"timestamp"`
Underlying string `json:"underlying"`
UnrealisedCost int64 `json:"unrealisedCost"`
UnrealisedGrossPnl int64 `json:"unrealisedGrossPnl"`
UnrealisedPnl int64 `json:"unrealisedPnl"`
UnrealisedPnlPcnt float64 `json:"unrealisedPnlPcnt"`
UnrealisedRoePcnt float64 `json:"unrealisedRoePcnt"`
UnrealisedTax int64 `json:"unrealisedTax"`
VarMargin int64 `json:"varMargin"`
}
// Quote Best Bid/Offer Snapshots & Historical Bins
type Quote struct {
AskPrice float64 `json:"askPrice"`
AskSize int64 `json:"askSize"`
BidPrice float64 `json:"bidPrice"`
BidSize int64 `json:"bidSize"`
Symbol string `json:"symbol"`
Timestamp string `json:"timestamp"`
}
// Settlement Historical Settlement Data
type Settlement struct {
Bankrupt int64 `json:"bankrupt"`
OptionStrikePrice float64 `json:"optionStrikePrice"`
OptionUnderlyingPrice float64 `json:"optionUnderlyingPrice"`
SettledPrice float64 `json:"settledPrice"`
SettlementType string `json:"settlementType"`
Symbol string `json:"symbol"`
TaxBase int64 `json:"taxBase"`
TaxRate float64 `json:"taxRate"`
Timestamp string `json:"timestamp"`
}
// Stats Exchange Statistics
type Stats struct {
Currency string `json:"currency"`
OpenInterest int64 `json:"openInterest"`
OpenValue int64 `json:"openValue"`
RootSymbol string `json:"rootSymbol"`
Turnover24h int64 `json:"turnover24h"`
Volume24h int64 `json:"volume24h"`
}
// StatsHistory stats history
type StatsHistory struct {
Currency string `json:"currency"`
Date string `json:"date"`
RootSymbol string `json:"rootSymbol"`
Turnover int64 `json:"turnover"`
Volume int64 `json:"volume"`
}
// StatsUSD contains summary of exchange stats
type StatsUSD struct {
Currency string `json:"currency"`
RootSymbol string `json:"rootSymbol"`
Turnover int64 `json:"turnover"`
Turnover24h int64 `json:"turnover24h"`
Turnover30d int64 `json:"turnover30d"`
Turnover365d int64 `json:"turnover365d"`
}
// Trade Individual & Bucketed Trades
type Trade struct {
ForeignNotional float64 `json:"foreignNotional"`
GrossValue int64 `json:"grossValue"`
HomeNotional float64 `json:"homeNotional"`
Price float64 `json:"price"`
Side string `json:"side"`
Size int64 `json:"size"`
Symbol string `json:"symbol"`
TickDirection string `json:"tickDirection"`
Timestamp string `json:"timestamp"`
TrdMatchID string `json:"trdMatchID"`
}
// User Account Operations
type User struct {
TFAEnabled string `json:"TFAEnabled"`
AffiliateID string `json:"affiliateID"`
Country string `json:"country"`
Created string `json:"created"`
Email string `json:"email"`
Firstname string `json:"firstname"`
GeoipCountry string `json:"geoipCountry"`
GeoipRegion string `json:"geoipRegion"`
ID int32 `json:"id"`
LastUpdated string `json:"lastUpdated"`
Lastname string `json:"lastname"`
OwnerID int32 `json:"ownerId"`
PgpPubKey string `json:"pgpPubKey"`
Phone string `json:"phone"`
Preferences UserPreferences `json:"preferences"`
Typ string `json:"typ"`
Username string `json:"username"`
}
// UserPreferences user preferences
type UserPreferences struct {
AlertOnLiquidations bool `json:"alertOnLiquidations"`
AnimationsEnabled bool `json:"animationsEnabled"`
AnnouncementsLastSeen string `json:"announcementsLastSeen"`
ChatChannelID float64 `json:"chatChannelID"`
ColorTheme string `json:"colorTheme"`
Currency string `json:"currency"`
Debug bool `json:"debug"`
DisableEmails []string `json:"disableEmails"`
HideConfirmDialogs []string `json:"hideConfirmDialogs"`
HideConnectionModal bool `json:"hideConnectionModal"`
HideFromLeaderboard bool `json:"hideFromLeaderboard"`
HideNameFromLeaderboard bool `json:"hideNameFromLeaderboard"`
HideNotifications []string `json:"hideNotifications"`
Locale string `json:"locale"`
MsgsSeen []string `json:"msgsSeen"`
OrderBookBinning interface{} `json:"orderBookBinning"`
OrderBookType string `json:"orderBookType"`
OrderClearImmediate bool `json:"orderClearImmediate"`
OrderControlsPlusMinus bool `json:"orderControlsPlusMinus"`
ShowLocaleNumbers bool `json:"showLocaleNumbers"`
Sounds []string `json:"sounds"`
StrictIPCheck bool `json:"strictIPCheck"`
StrictTimeout bool `json:"strictTimeout"`
TickerGroup string `json:"tickerGroup"`
TickerPinned bool `json:"tickerPinned"`
TradeLayout string `json:"tradeLayout"`
}
// AffiliateStatus affiliate Status details
type AffiliateStatus struct {
Account int64 `json:"account"`
Currency string `json:"currency"`
ExecComm int64 `json:"execComm"`
ExecTurnover int64 `json:"execTurnover"`
PayoutPcnt float64 `json:"payoutPcnt"`
PendingPayout int64 `json:"pendingPayout"`
PrevComm int64 `json:"prevComm"`
PrevPayout int64 `json:"prevPayout"`
PrevTimestamp string `json:"prevTimestamp"`
PrevTurnover int64 `json:"prevTurnover"`
ReferrerAccount float64 `json:"referrerAccount"`
Timestamp string `json:"timestamp"`
TotalComm int64 `json:"totalComm"`
TotalReferrals int64 `json:"totalReferrals"`
TotalTurnover int64 `json:"totalTurnover"`
}
// TransactionInfo Information
type TransactionInfo struct {
Account int64 `json:"account"`
Address string `json:"address"`
Amount int64 `json:"amount"`
Currency string `json:"currency"`
Fee int64 `json:"fee"`
Text string `json:"text"`
Timestamp string `json:"timestamp"`
TransactID string `json:"transactID"`
TransactStatus string `json:"transactStatus"`
TransactTime string `json:"transactTime"`
TransactType string `json:"transactType"`
Tx string `json:"tx"`
}
// UserCommission user commission
type UserCommission struct {
MakerFee float64 `json:"makerFee"`
MaxFee float64 `json:"maxFee"`
SettlementFee float64 `json:"settlementFee"`
TakerFee float64 `json:"takerFee"`
}
// ConfirmEmail confirmatin email endpoint data
type ConfirmEmail struct {
ID string `json:"id"`
TTL int64 `json:"ttl"`
Created string `json:"created"`
UserID int64 `json:"userId"`
}
// UserMargin margin information
type UserMargin struct {
Account int64 `json:"account"`
Action string `json:"action"`
Amount int64 `json:"amount"`
AvailableMargin int64 `json:"availableMargin"`
Commission float64 `json:"commission"`
ConfirmedDebit int64 `json:"confirmedDebit"`
Currency string `json:"currency"`
ExcessMargin int64 `json:"excessMargin"`
ExcessMarginPcnt float64 `json:"excessMarginPcnt"`
GrossComm int64 `json:"grossComm"`
GrossExecCost int64 `json:"grossExecCost"`
GrossLastValue int64 `json:"grossLastValue"`
GrossMarkValue int64 `json:"grossMarkValue"`
GrossOpenCost int64 `json:"grossOpenCost"`
GrossOpenPremium int64 `json:"grossOpenPremium"`
IndicativeTax int64 `json:"indicativeTax"`
InitMargin int64 `json:"initMargin"`
MaintMargin int64 `json:"maintMargin"`
MarginBalance int64 `json:"marginBalance"`
MarginBalancePcnt float64 `json:"marginBalancePcnt"`
MarginLeverage float64 `json:"marginLeverage"`
MarginUsedPcnt float64 `json:"marginUsedPcnt"`
PendingCredit int64 `json:"pendingCredit"`
PendingDebit int64 `json:"pendingDebit"`
PrevRealisedPnl int64 `json:"prevRealisedPnl"`
PrevState string `json:"prevState"`
PrevUnrealisedPnl int64 `json:"prevUnrealisedPnl"`
RealisedPnl int64 `json:"realisedPnl"`
RiskLimit int64 `json:"riskLimit"`
RiskValue int64 `json:"riskValue"`
SessionMargin int64 `json:"sessionMargin"`
State string `json:"state"`
SyntheticMargin int64 `json:"syntheticMargin"`
TargetExcessMargin int64 `json:"targetExcessMargin"`
TaxableMargin int64 `json:"taxableMargin"`
Timestamp string `json:"timestamp"`
UnrealisedPnl int64 `json:"unrealisedPnl"`
UnrealisedProfit int64 `json:"unrealisedProfit"`
VarMargin int64 `json:"varMargin"`
WalletBalance int64 `json:"walletBalance"`
WithdrawableMargin int64 `json:"withdrawableMargin"`
}
// MinWithdrawalFee minimum withdrawal fee information
type MinWithdrawalFee struct {
Currency string `json:"currency"`
Fee int64 `json:"fee"`
MinFee int64 `json:"minFee"`
}
// WalletInfo wallet information
type WalletInfo struct {
Account int64 `json:"account"`
Addr string `json:"addr"`
Amount int64 `json:"amount"`
ConfirmedDebit int64 `json:"confirmedDebit"`
Currency string `json:"currency"`
DeltaAmount int64 `json:"deltaAmount"`
DeltaDeposited int64 `json:"deltaDeposited"`
DeltaTransferIn int64 `json:"deltaTransferIn"`
DeltaTransferOut int64 `json:"deltaTransferOut"`
DeltaWithdrawn int64 `json:"deltaWithdrawn"`
Deposited int64 `json:"deposited"`
PendingCredit int64 `json:"pendingCredit"`
PendingDebit int64 `json:"pendingDebit"`
PrevAmount int64 `json:"prevAmount"`
PrevDeposited int64 `json:"prevDeposited"`
PrevTimestamp string `json:"prevTimestamp"`
PrevTransferIn int64 `json:"prevTransferIn"`
PrevTransferOut int64 `json:"prevTransferOut"`
PrevWithdrawn int64 `json:"prevWithdrawn"`
Script string `json:"script"`
Timestamp string `json:"timestamp"`
TransferIn int64 `json:"transferIn"`
TransferOut int64 `json:"transferOut"`
WithdrawalLock []string `json:"withdrawalLock"`
Withdrawn int64 `json:"withdrawn"`
}

View File

@@ -0,0 +1,494 @@
package bitmex
import (
"errors"
"fmt"
"log"
"strconv"
"time"
"github.com/gorilla/websocket"
"github.com/thrasher-/gocryptotrader/common"
)
const (
bitmexWSURL = "wss://www.bitmex.com/realtime"
// Public Subscription Channels
bitmexWSAnnouncement = "announcement"
bitmexWSChat = "chat"
bitmexWSConnected = "connected"
bitmexWSFunding = "funding"
bitmexWSInstrument = "instrument"
bitmexWSInsurance = "insurance"
bitmexWSLiquidation = "liquidation"
bitmexWSOrderbookL2 = "orderBookL2"
bitmexWSOrderbookL10 = "orderBook10"
bitmexWSPublicNotifications = "publicNotifications"
bitmexWSQuote = "quote"
bitmexWSQuote1m = "quoteBin1m"
bitmexWSQuote5m = "quoteBin5m"
bitmexWSQuote1h = "quoteBin1h"
bitmexWSQuote1d = "quoteBin1d"
bitmexWSSettlement = "settlement"
bitmexWSTrade = "trade"
bitmexWSTrade1m = "tradeBin1m"
bitmexWSTrade5m = "tradeBin5m"
bitmexWSTrade1h = "tradeBin1h"
bitmexWSTrade1d = "tradeBin1d"
// Authenticated Subscription Channels
bitmexWSAffiliate = "affiliate"
bitmexWSExecution = "execution"
bitmexWSOrder = "order"
bitmexWSMargin = "margin"
bitmexWSPosition = "position"
bitmexWSPrivateNotifications = "privateNotifications"
bitmexWSTransact = "transact"
bitmexWSWallet = "wallet"
bitmexActionInitialData = "partial"
bitmexActionInsertData = "insert"
bitmexActionDeleteData = "delete"
bitmexActionUpdateData = "update"
)
var (
pongChan = make(chan int, 1)
timer *time.Timer
)
// WebsocketConnect initiates a new websocket connection
func (b *Bitmex) WebsocketConnect() error {
var dialer websocket.Dialer
var err error
b.WebsocketConn, _, err = dialer.Dial(bitmexWSURL, nil)
if err != nil {
return err
}
_, p, err := b.WebsocketConn.ReadMessage()
if err != nil {
return err
}
var welcomeResp WebsocketWelcome
err = common.JSONDecode(p, &welcomeResp)
if err != nil {
return err
}
go b.connectionHandler()
if b.Verbose {
log.Printf("Successfully connected to Bitmex %s at time: %s Limit: %d",
welcomeResp.Info,
welcomeResp.Timestamp,
welcomeResp.Limit.Remaining)
}
go b.handleIncomingData()
err = b.websocketSubscribe()
if err != nil {
b.WebsocketConn.Close()
return err
}
if b.AuthenticatedAPISupport {
err := b.websocketSendAuth()
if err != nil {
log.Fatal(err)
}
}
return nil
}
// Timer handles connection loss or failure
func (b *Bitmex) connectionHandler() {
defer func() {
if b.Verbose {
log.Println("Bitmex websocket: Connection handler routine shutdown")
}
}()
shutdown := b.shutdown.addRoutine()
timer = time.NewTimer(5 * time.Second)
for {
select {
case <-timer.C:
timeout := time.After(5 * time.Second)
err := b.WebsocketConn.WriteJSON("ping")
if err != nil {
b.reconnect()
return
}
for {
select {
case <-pongChan:
if b.Verbose {
log.Println("Bitmex websocket: PONG received")
}
break
case <-timeout:
log.Println("Bitmex websocket: Connection timed out - Closing connection....")
b.WebsocketConn.Close()
log.Println("Bitmex websocket: Connection timed out - Reconnecting...")
b.reconnect()
return
}
}
case <-shutdown:
log.Println("Bitmex websocket: shutdown requested - Closing connection....")
b.WebsocketConn.Close()
log.Println("Bitmex websocket: Sending shutdown message")
b.shutdown.routineShutdown()
return
}
}
}
// Reconnect handles reconnections to websocket API
func (b *Bitmex) reconnect() {
for {
err := b.WebsocketConnect()
if err != nil {
log.Println("Bitmex websocket: Connection timed out - Failed to connect, sleeping...")
time.Sleep(time.Second * 2)
continue
}
return
}
}
// handleIncomingData services incoming data from the websocket connection
func (b *Bitmex) handleIncomingData() {
defer func() {
if b.Verbose {
log.Println("Bitmex websocket: Response data handler routine shutdown")
}
}()
for {
_, resp, err := b.WebsocketConn.ReadMessage()
if err != nil {
if b.Verbose {
log.Println("Bitmex websocket: Connection error", err)
}
return
}
message := string(resp)
if common.StringContains(message, "pong") {
if b.Verbose {
log.Println("Bitmex websocket: PONG receieved")
}
pongChan <- 1
continue
}
if common.StringContains(message, "ping") {
err = b.WebsocketConn.WriteJSON("pong")
if err != nil {
if b.Verbose {
log.Println("Bitmex websocket error: ", err)
}
return
}
}
if !timer.Reset(5 * time.Second) {
log.Fatal("Bitmex websocket: Timer failed to set")
}
quickCapture := make(map[string]interface{})
err = common.JSONDecode(resp, &quickCapture)
if err != nil {
log.Fatal(err)
}
var respError WebsocketErrorResponse
if _, ok := quickCapture["status"]; ok {
err = common.JSONDecode(resp, &respError)
if err != nil {
log.Fatal(err)
}
log.Printf("Bitmex websocket error: %s", respError.Error)
continue
}
if _, ok := quickCapture["success"]; ok {
var decodedResp WebsocketSubscribeResp
err := common.JSONDecode(resp, &decodedResp)
if err != nil {
log.Fatal(err)
}
if decodedResp.Success {
if b.Verbose {
if len(quickCapture) == 3 {
log.Printf("Bitmex Websocket: Successfully subscribed to %s",
decodedResp.Subscribe)
} else {
log.Println("Bitmex Websocket: Successfully authenticated websocket connection")
}
}
continue
}
log.Printf("Bitmex websocket error: Unable to subscribe %s",
decodedResp.Subscribe)
} else if _, ok := quickCapture["table"]; ok {
var decodedResp WebsocketMainResponse
err := common.JSONDecode(resp, &decodedResp)
if err != nil {
log.Fatal(err)
}
switch decodedResp.Table {
case bitmexWSOrderbookL2:
var orderbooks OrderBookData
err = common.JSONDecode(resp, &orderbooks)
if err != nil {
log.Fatal(err)
}
err = b.processOrderbook(orderbooks.Data, orderbooks.Action)
if err != nil {
log.Fatal(err)
}
case bitmexWSTrade:
var trades TradeData
err = common.JSONDecode(resp, &trades)
if err != nil {
log.Fatal(err)
}
err = b.processTrades(trades.Data, trades.Action)
if err != nil {
log.Fatal(err)
}
case bitmexWSAnnouncement:
var announcement AnnouncementData
err = common.JSONDecode(resp, &announcement)
if err != nil {
log.Fatal(err)
}
err = b.processAnnouncement(announcement.Data, announcement.Action)
if err != nil {
log.Fatal(err)
}
default:
log.Fatal("Bitmex websocket error: Table unknown -", decodedResp.Table)
}
}
}
}
// Temporary local cache of Announcements
var localAnnouncements []Announcement
var partialLoadedAnnouncement bool
// ProcessAnnouncement process announcements
func (b *Bitmex) processAnnouncement(data []Announcement, action string) error {
switch action {
case bitmexActionInitialData:
if !partialLoadedAnnouncement {
localAnnouncements = data
}
partialLoadedAnnouncement = true
default:
return fmt.Errorf("Bitmex websocket error: ProcessAnnouncement() unallocated action - %s",
action)
}
return nil
}
// Temporary local cache of orderbooks
var localOb []OrderBookL2
var partialLoaded bool
// ProcessOrderbook processes orderbook updates
func (b *Bitmex) processOrderbook(data []OrderBookL2, action string) error {
switch action {
case bitmexActionInitialData:
if !partialLoaded {
localOb = data
}
partialLoaded = true
case bitmexActionUpdateData:
if partialLoaded {
updated := len(data)
for _, elem := range data {
for i := range localOb {
if localOb[i].ID == elem.ID && localOb[i].Symbol == elem.Symbol {
localOb[i].Side = elem.Side
localOb[i].Size = elem.Size
updated--
break
}
}
}
if updated != 0 {
return errors.New("Bitmex websocket error: Elements not updated correctly")
}
}
case bitmexActionInsertData:
if partialLoaded {
updated := len(data)
for _, elem := range data {
localOb = append(localOb, OrderBookL2{
Symbol: elem.Symbol,
ID: elem.ID,
Side: elem.Side,
Size: elem.Size,
Price: elem.Price,
})
updated--
}
if updated != 0 {
return errors.New("Bitmex websocket error: Elements not updated correctly")
}
}
case bitmexActionDeleteData:
if partialLoaded {
updated := len(data)
for _, elem := range data {
for i := range localOb {
if localOb[i].ID == elem.ID && localOb[i].Symbol == elem.Symbol {
localOb[i] = localOb[len(localOb)-1]
localOb = localOb[:len(localOb)-1]
updated--
break
}
}
}
if updated != 0 {
return errors.New("Bitmex websocket error: Elements not updated correctly")
}
}
}
return nil
}
// Temporary local cache of orderbooks
var localTrades []Trade
var partialLoadedTrades bool
// ProcessTrades processes new trades that have occured
func (b *Bitmex) processTrades(data []Trade, action string) error {
switch action {
case bitmexActionInitialData:
if !partialLoadedTrades {
localTrades = data
}
partialLoadedTrades = true
case bitmexActionInsertData:
if partialLoadedTrades {
localTrades = append(localTrades, data...)
}
default:
return fmt.Errorf("Bitmex websocket error: ProcessTrades() unallocated action - %s",
action)
}
return nil
}
// WebsocketSubscribe subscribes to a websocket channel
func (b *Bitmex) websocketSubscribe() error {
contracts := b.GetEnabledCurrencies()
// Subscriber
var subscriber WebsocketRequest
subscriber.Command = "subscribe"
// Announcement subscribe
subscriber.Arguments = append(subscriber.Arguments, bitmexWSAnnouncement)
for _, contract := range contracts {
// Orderbook subscribe
subscriber.Arguments = append(subscriber.Arguments,
bitmexWSOrderbookL2+":"+contract.Pair().String())
// Trade subscribe
subscriber.Arguments = append(subscriber.Arguments,
bitmexWSTrade+":"+contract.Pair().String())
// NOTE more added here in future
}
err := b.WebsocketConn.WriteJSON(subscriber)
if err != nil {
return err
}
return nil
}
// WebsocketSendAuth sends an authenticated subscription
func (b *Bitmex) websocketSendAuth() error {
timestamp := time.Now().Add(time.Hour * 1).Unix()
newTimestamp := strconv.FormatInt(timestamp, 10)
hmac := common.GetHMAC(common.HashSHA256,
[]byte("GET/realtime"+newTimestamp),
[]byte(b.APISecret))
signature := common.HexEncodeToString(hmac)
var sendAuth WebsocketRequest
sendAuth.Command = "authKeyExpires"
sendAuth.Arguments = append(sendAuth.Arguments, b.APIKey)
sendAuth.Arguments = append(sendAuth.Arguments, timestamp)
sendAuth.Arguments = append(sendAuth.Arguments, signature)
return b.WebsocketConn.WriteJSON(sendAuth)
}
// Shutdown to monitor and shut down routines package specific
type Shutdown struct {
c chan int
routineCount int
finishC chan int
}
// NewRoutineManagement returns an new initial routine management system
func (b *Bitmex) NewRoutineManagement() *Shutdown {
return &Shutdown{
c: make(chan int, 1),
finishC: make(chan int, 1),
}
}
// AddRoutine adds a routine to the monitor and returns a channel
func (r *Shutdown) addRoutine() chan int {
log.Println("Bitmex Websocket: Routine added to monitor")
r.routineCount++
return r.c
}
// RoutineShutdown sends a message to the finisher channel
func (r *Shutdown) routineShutdown() {
log.Println("Bitmex Websocket: Routine is shutting down")
r.finishC <- 1
}
// SignalShutdown signals a shutdown across routines
func (r *Shutdown) SignalShutdown() {
log.Println("Bitmex Websocket: Shutdown signal sending..")
for i := 0; i < r.routineCount; i++ {
log.Printf("Bitmex Websocket: Shutdown signal sent to routine %d", i+1)
r.c <- 1
}
for {
<-r.finishC
r.routineCount--
if r.routineCount <= 0 {
close(r.c)
close(r.finishC)
log.Println("Bitmex Websocket: All routines stopped")
return
}
}
}

View File

@@ -0,0 +1,72 @@
package bitmex
// WebsocketRequest is the main request type
type WebsocketRequest struct {
Command string `json:"op"`
Arguments []interface{} `json:"args"`
}
// WebsocketErrorResponse main error response
type WebsocketErrorResponse struct {
Status int `json:"status"`
Error string `json:"error"`
Meta interface{} `json:"meta"`
Request WebsocketRequest `json:"request"`
}
// WebsocketWelcome initial welcome type
type WebsocketWelcome struct {
Info string `json:"info"`
Version string `json:"version"`
Timestamp string `json:"timestamp"`
Docs string `json:"docs"`
Limit struct {
Remaining int64 `json:"remaining"`
} `json:"limit"`
}
// WebsocketSubscribeResp is a response that occurs after a subscription
type WebsocketSubscribeResp struct {
Success bool `json:"success"`
Subscribe string `json:"subscribe"`
Request WebsocketRequest `json:"request"`
}
// WebsocketMainResponse main table defined response
type WebsocketMainResponse struct {
Table string `json:"table"`
Keys []string `json:"keys"`
Types struct {
ID string `json:"id"`
Price string `json:"price"`
Side string `json:"side"`
Size string `json:"size"`
Symbol string `json:"symbol"`
} `json:"types"`
ForeignKeys struct {
Side string `json:"side"`
Symbol string `json:"symbol"`
} `json:"foreignKeys"`
Attributes struct {
ID string `json:"id"`
Symbol string `json:"symbol"`
} `json:"Attributes"`
}
// OrderBookData contains orderbook resp data with action to be taken
type OrderBookData struct {
Data []OrderBookL2 `json:"data"`
Action string `json:"action"`
}
// TradeData contains trade resp data with action to be taken
type TradeData struct {
Data []Trade `json:"data"`
Action string `json:"action"`
}
// AnnouncementData contains announcement resp data with action to be taken
type AnnouncementData struct {
Data []Announcement `json:"data"`
Action string `json:"action"`
}

View File

@@ -0,0 +1,195 @@
package bitmex
import (
"errors"
"log"
"sync"
"time"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/pair"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
// Start starts the Bitmex go routine
func (b *Bitmex) Start(wg *sync.WaitGroup) {
wg.Add(1)
go func() {
b.Run()
wg.Done()
}()
}
// Run implements the Bitmex wrapper
func (b *Bitmex) Run() {
if b.Verbose {
log.Printf("%s Websocket: %s. (url: %s).\n", b.GetName(), common.IsEnabled(b.Websocket), b.WebsocketURL)
log.Printf("%s polling delay: %ds.\n", b.GetName(), b.RESTPollingDelay)
log.Printf("%s %d currencies enabled: %s.\n", b.GetName(), len(b.EnabledPairs), b.EnabledPairs)
}
marketInfo, err := b.GetActiveInstruments(GenericRequestParams{})
if err != nil {
log.Printf("%s Failed to get available symbols.\n", b.GetName())
} else {
var exchangeProducts []string
for _, info := range marketInfo {
exchangeProducts = append(exchangeProducts, info.Symbol)
}
err = b.UpdateCurrencies(exchangeProducts, false, false)
if err != nil {
log.Printf("%s Failed to update available currencies.\n", b.GetName())
}
}
}
// UpdateTicker updates and returns the ticker for a currency pair
func (b *Bitmex) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
var tickerPrice ticker.Price
currency := exchange.FormatExchangeCurrency(b.Name, p)
tick, err := b.GetTrade(GenericRequestParams{
Symbol: currency.String(),
StartTime: time.Now().Format(time.RFC3339),
Reverse: true,
Count: 1})
if err != nil {
return tickerPrice, err
}
if len(tick) == 0 {
return tickerPrice, errors.New("Bitmex REST error: no ticker return")
}
tickerPrice.Pair = p
tickerPrice.LastUpdated = time.Now()
tickerPrice.CurrencyPair = tick[0].Symbol
tickerPrice.Last = tick[0].Price
tickerPrice.Volume = float64(tick[0].Size)
ticker.ProcessTicker(b.Name, p, tickerPrice, assetType)
return tickerPrice, nil
}
// GetTickerPrice returns the ticker for a currency pair
func (b *Bitmex) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
tickerNew, err := ticker.GetTicker(b.GetName(), p, assetType)
if err != nil {
return b.UpdateTicker(p, assetType)
}
return tickerNew, nil
}
// GetOrderbookEx returns orderbook base on the currency pair
func (b *Bitmex) GetOrderbookEx(currency pair.CurrencyPair, assetType string) (orderbook.Base, error) {
ob, err := orderbook.GetOrderbook(b.GetName(), currency, assetType)
if err != nil {
return b.UpdateOrderbook(currency, assetType)
}
return ob, nil
}
// UpdateOrderbook updates and returns the orderbook for a currency pair
func (b *Bitmex) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
var orderBook orderbook.Base
orderbookNew, err := b.GetOrderbook(OrderBookGetL2Params{
Symbol: exchange.FormatExchangeCurrency(b.Name, p).String(),
Depth: 500})
if err != nil {
return orderBook, err
}
for _, ob := range orderbookNew {
if ob.Side == "Sell" {
orderBook.Asks = append(orderBook.Asks,
orderbook.Item{Amount: float64(ob.Size), Price: ob.Price})
continue
}
if ob.Side == "Buy" {
orderBook.Bids = append(orderBook.Bids,
orderbook.Item{Amount: float64(ob.Size), Price: ob.Price})
continue
}
}
orderbook.ProcessOrderbook(b.GetName(), p, orderBook, assetType)
return orderbook.GetOrderbook(b.Name, p, assetType)
}
// GetExchangeAccountInfo retrieves balances for all enabled currencies for the
// Bitmex exchange
func (b *Bitmex) GetExchangeAccountInfo() (exchange.AccountInfo, error) {
var response exchange.AccountInfo
return response, errors.New("not implemented")
}
// GetExchangeFundTransferHistory returns funding history, deposits and
// withdrawals
func (b *Bitmex) GetExchangeFundTransferHistory() ([]exchange.FundHistory, error) {
var fundHistory []exchange.FundHistory
return fundHistory, errors.New("not supported on exchange")
}
// GetExchangeHistory returns historic trade data since exchange opening.
func (b *Bitmex) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]exchange.TradeHistory, error) {
var resp []exchange.TradeHistory
return resp, errors.New("trade history not yet implemented")
}
// SubmitExchangeOrder submits a new order
func (b *Bitmex) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) {
return 0, errors.New("not yet implemented")
}
// ModifyExchangeOrder will allow of changing orderbook placement and limit to
// market conversion
func (b *Bitmex) ModifyExchangeOrder(orderID int64, action exchange.ModifyOrder) (int64, error) {
return 0, errors.New("not yet implemented")
}
// CancelExchangeOrder cancels an order by its corresponding ID number
func (b *Bitmex) CancelExchangeOrder(orderID int64) error {
return errors.New("not yet implemented")
}
// CancelAllExchangeOrders cancels all orders associated with a currency pair
func (b *Bitmex) CancelAllExchangeOrders() error {
return errors.New("not yet implemented")
}
// GetExchangeOrderInfo returns information on a current open order
func (b *Bitmex) GetExchangeOrderInfo(orderID int64) (exchange.OrderDetail, error) {
var orderDetail exchange.OrderDetail
return orderDetail, errors.New("not yet implemented")
}
// GetExchangeDepositAddress returns a deposit address for a specified currency
func (b *Bitmex) GetExchangeDepositAddress(cryptocurrency pair.CurrencyItem) (string, error) {
return "", errors.New("not yet implemented")
}
// WithdrawCryptoExchangeFunds returns a withdrawal ID when a withdrawal is
// submitted
func (b *Bitmex) WithdrawCryptoExchangeFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) {
return "", errors.New("not yet implemented")
}
// WithdrawFiatExchangeFunds returns a withdrawal ID when a withdrawal is
// submitted
func (b *Bitmex) WithdrawFiatExchangeFunds(currency pair.CurrencyItem, amount float64) (string, error) {
return "", errors.New("not yet implemented")
}
// WithdrawExchangeFiatFundsToInternationalBank returns a withdrawal ID when a withdrawal is
// submitted
func (b *Bitmex) WithdrawExchangeFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) {
return "", errors.New("not yet implemented")
}

File diff suppressed because one or more lines are too long

View File

@@ -85,6 +85,7 @@ func (b *Bitstamp) Setup(exch config.ExchangeConfig) {
b.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
b.SetAPIKeys(exch.APIKey, exch.APISecret, exch.ClientID, false)
b.SetHTTPClientTimeout(exch.HTTPTimeout)
b.SetHTTPClientUserAgent(exch.HTTPUserAgent)
b.RESTPollingDelay = exch.RESTPollingDelay
b.Verbose = exch.Verbose
b.Websocket = exch.Websocket

View File

@@ -88,6 +88,7 @@ func (b *Bittrex) Setup(exch config.ExchangeConfig) {
b.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
b.SetAPIKeys(exch.APIKey, exch.APISecret, exch.ClientID, false)
b.SetHTTPClientTimeout(exch.HTTPTimeout)
b.SetHTTPClientUserAgent(exch.HTTPUserAgent)
b.RESTPollingDelay = exch.RESTPollingDelay
b.Verbose = exch.Verbose
b.Websocket = exch.Websocket

View File

@@ -79,6 +79,7 @@ func (b *BTCC) Setup(exch config.ExchangeConfig) {
b.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
b.SetAPIKeys(exch.APIKey, exch.APISecret, "", false)
b.SetHTTPClientTimeout(exch.HTTPTimeout)
b.SetHTTPClientUserAgent(exch.HTTPUserAgent)
b.RESTPollingDelay = exch.RESTPollingDelay
b.Verbose = exch.Verbose
b.Websocket = exch.Websocket

View File

@@ -76,6 +76,7 @@ func (b *BTCMarkets) Setup(exch config.ExchangeConfig) {
b.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
b.SetAPIKeys(exch.APIKey, exch.APISecret, "", true)
b.SetHTTPClientTimeout(exch.HTTPTimeout)
b.SetHTTPClientUserAgent(exch.HTTPUserAgent)
b.RESTPollingDelay = exch.RESTPollingDelay
b.Verbose = exch.Verbose
b.Websocket = exch.Websocket

View File

@@ -87,6 +87,7 @@ func (c *CoinbasePro) Setup(exch config.ExchangeConfig) {
c.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
c.SetAPIKeys(exch.APIKey, exch.APISecret, exch.ClientID, true)
c.SetHTTPClientTimeout(exch.HTTPTimeout)
c.SetHTTPClientUserAgent(exch.HTTPUserAgent)
c.RESTPollingDelay = exch.RESTPollingDelay
c.Verbose = exch.Verbose
c.Websocket = exch.Websocket

View File

@@ -74,6 +74,7 @@ func (c *COINUT) Setup(exch config.ExchangeConfig) {
c.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
c.SetAPIKeys(exch.APIKey, exch.APISecret, exch.ClientID, true)
c.SetHTTPClientTimeout(exch.HTTPTimeout)
c.SetHTTPClientUserAgent(exch.HTTPUserAgent)
c.RESTPollingDelay = exch.RESTPollingDelay
c.Verbose = exch.Verbose
c.Websocket = exch.Websocket

View File

@@ -102,6 +102,7 @@ type Base struct {
SupportsAutoPairUpdating bool
SupportsRESTTickerBatching bool
HTTPTimeout time.Duration
HTTPUserAgent string
WebsocketURL string
APIUrl string
RequestCurrencyPairFormat config.CurrencyPairFormatConfig
@@ -175,6 +176,20 @@ func (e *Base) GetHTTPClient() *http.Client {
return e.Requester.HTTPClient
}
// SetHTTPClientUserAgent sets the exchanges HTTP user agent
func (e *Base) SetHTTPClientUserAgent(ua string) {
if e.Requester == nil {
e.Requester = request.New(e.Name, request.NewRateLimit(time.Second, 0), request.NewRateLimit(time.Second, 0), new(http.Client))
}
e.Requester.UserAgent = ua
e.HTTPUserAgent = ua
}
// GetHTTPClientUserAgent gets the exchanges HTTP user agent
func (e *Base) GetHTTPClientUserAgent() string {
return e.HTTPUserAgent
}
// SetAutoPairDefaults sets the default values for whether or not the exchange
// supports auto pair updating or not
func (e *Base) SetAutoPairDefaults() error {

View File

@@ -77,6 +77,7 @@ func (e *EXMO) Setup(exch config.ExchangeConfig) {
e.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
e.SetAPIKeys(exch.APIKey, exch.APISecret, "", false)
e.SetHTTPClientTimeout(exch.HTTPTimeout)
e.SetHTTPClientUserAgent(exch.HTTPUserAgent)
e.RESTPollingDelay = exch.RESTPollingDelay
e.Verbose = exch.Verbose
e.Websocket = exch.Websocket

View File

@@ -1,9 +1,140 @@
# GoCryptoTrader package gateio
# GoCryptoTrader package Gateio
<img src="https://github.com/thrasher-/gocryptotrader/blob/master/web/src/assets/page-logo.png?raw=true" width="350px" height="350px" hspace="70">
[![Build Status](https://travis-ci.org/thrasher-/gocryptotrader.svg?branch=master)](https://travis-ci.org/thrasher-/gocryptotrader)
[![Software License](https://img.shields.io/badge/License-MIT-orange.svg?style=flat-square)](https://github.com/thrasher-/gocryptotrader/blob/master/LICENSE)
[![GoDoc](https://godoc.org/github.com/thrasher-/gocryptotrader?status.svg)](https://godoc.org/github.com/thrasher-/gocryptotrader/exchanges/gateio)
[![Coverage Status](http://codecov.io/github/thrasher-/gocryptotrader/coverage.svg?branch=master)](http://codecov.io/github/thrasher-/gocryptotrader?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/thrasher-/gocryptotrader)](https://goreportcard.com/report/github.com/thrasher-/gocryptotrader)
This gateio package is part of the GoCryptoTrader codebase.
## Gateio Exchange
## This is still in active development
You can track ideas, planned features and what's in progresss on this Trello board: [https://trello.com/b/ZAhMhpOy/gocryptotrader](https://trello.com/b/ZAhMhpOy/gocryptotrader).
Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader Slack](https://gocryptotrader.herokuapp.com/)
## GateIO Exchange
### Current Features
Gateio 交易所的支持支持获取K线、支持的交易对、交易市场参数、买/卖订单、取消订单
+ REST functions
### How to enable
+ [Enable via configuration](https://github.com/thrasher-/gocryptotrader/tree/master/config#enable-exchange-via-config-example)
+ Individual package example below:
```go
// Exchanges will be abstracted out in further updates and examples will be
// supplied then
```
### How to do REST public/private calls
+ If enabled via "configuration".json file the exchange will be added to the
IBotExchange array in the ```go var bot Bot``` and you will only be able to use
the wrapper interface functions for accessing exchange data. View routines.go
for an example of integration usage with GoCryptoTrader. Rudimentary example
below:
main.go
```go
var g exchange.IBotExchange
for i := range bot.exchanges {
if bot.exchanges[i].GetName() == "GateIO" {
g = bot.exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
tick, err := g.GetTickerPrice()
if err != nil {
// Handle error
}
// Fetches current orderbook information
ob, err := g.GetOrderbookEx()
if err != nil {
// Handle error
}
// Private calls - wrapper functions - make sure your APIKEY and APISECRET are
// set and AuthenticatedAPISupport is set to true
// Fetches current account information
accountInfo, err := g.GetExchangeAccountInfo()
if err != nil {
// Handle error
}
```
+ If enabled via individually importing package, rudimentary example below:
```go
// Public calls
// Fetches current ticker information
ticker, err := g.GetTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
ob, err := g.GetOrderBook()
if err != nil {
// Handle error
}
// Private calls - make sure your APIKEY and APISECRET are set and
// AuthenticatedAPISupport is set to true
// GetUserInfo returns account info
accountInfo, err := g.GetUserInfo(...)
if err != nil {
// Handle error
}
// Submits an order and the exchange and returns its tradeID
tradeID, err := g.Trade(...)
if err != nil {
// Handle error
}
```
### How to do LongPolling public/private calls
```go
// Exchanges will be abstracted out in further updates and examples will be
// supplied then
```
### Please click GoDocs chevron above to view current GoDoc information for this package
## Contribution
Please feel free to submit any pull requests or suggest any desired features to be added.
When submitting a PR, please abide by our coding guidelines:
+ Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting) guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)).
+ Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary) guidelines.
+ Code must adhere to our [coding style](https://github.com/thrasher-/gocryptotrader/blob/master/doc/coding_style.md).
+ Pull requests need to be based on and opened against the `master` branch.
## Donations
<img src="https://github.com/thrasher-/gocryptotrader/blob/master/web/src/assets/donate.png?raw=true" hspace="70">
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
***1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB***

View File

@@ -67,6 +67,7 @@ func (g *Gateio) Setup(exch config.ExchangeConfig) {
g.SetAPIKeys(exch.APIKey, exch.APISecret, "", false)
g.APIAuthPEMKey = exch.APIAuthPEMKey
g.SetHTTPClientTimeout(exch.HTTPTimeout)
g.SetHTTPClientUserAgent(exch.HTTPUserAgent)
g.RESTPollingDelay = exch.RESTPollingDelay
g.Verbose = exch.Verbose
g.Websocket = exch.Websocket

View File

@@ -121,6 +121,7 @@ func (g *Gemini) Setup(exch config.ExchangeConfig) {
g.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
g.SetAPIKeys(exch.APIKey, exch.APISecret, "", false)
g.SetHTTPClientTimeout(exch.HTTPTimeout)
g.SetHTTPClientUserAgent(exch.HTTPUserAgent)
g.RESTPollingDelay = exch.RESTPollingDelay
g.Verbose = exch.Verbose
g.Websocket = exch.Websocket

View File

@@ -78,6 +78,7 @@ func (p *HitBTC) Setup(exch config.ExchangeConfig) {
p.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
p.SetAPIKeys(exch.APIKey, exch.APISecret, "", false)
p.SetHTTPClientTimeout(exch.HTTPTimeout)
p.SetHTTPClientUserAgent(exch.HTTPUserAgent)
p.RESTPollingDelay = exch.RESTPollingDelay // Max 60000ms
p.Verbose = exch.Verbose
p.Websocket = exch.Websocket

View File

@@ -90,6 +90,7 @@ func (h *HUOBI) Setup(exch config.ExchangeConfig) {
h.SetAPIKeys(exch.APIKey, exch.APISecret, "", false)
h.APIAuthPEMKey = exch.APIAuthPEMKey
h.SetHTTPClientTimeout(exch.HTTPTimeout)
h.SetHTTPClientUserAgent(exch.HTTPUserAgent)
h.RESTPollingDelay = exch.RESTPollingDelay
h.Verbose = exch.Verbose
h.Websocket = exch.Websocket

View File

@@ -0,0 +1,140 @@
# GoCryptoTrader package Huobihadax
<img src="https://github.com/thrasher-/gocryptotrader/blob/master/web/src/assets/page-logo.png?raw=true" width="350px" height="350px" hspace="70">
[![Build Status](https://travis-ci.org/thrasher-/gocryptotrader.svg?branch=master)](https://travis-ci.org/thrasher-/gocryptotrader)
[![Software License](https://img.shields.io/badge/License-MIT-orange.svg?style=flat-square)](https://github.com/thrasher-/gocryptotrader/blob/master/LICENSE)
[![GoDoc](https://godoc.org/github.com/thrasher-/gocryptotrader?status.svg)](https://godoc.org/github.com/thrasher-/gocryptotrader/exchanges/huobihadax)
[![Coverage Status](http://codecov.io/github/thrasher-/gocryptotrader/coverage.svg?branch=master)](http://codecov.io/github/thrasher-/gocryptotrader?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/thrasher-/gocryptotrader)](https://goreportcard.com/report/github.com/thrasher-/gocryptotrader)
This huobihadax package is part of the GoCryptoTrader codebase.
## This is still in active development
You can track ideas, planned features and what's in progresss on this Trello board: [https://trello.com/b/ZAhMhpOy/gocryptotrader](https://trello.com/b/ZAhMhpOy/gocryptotrader).
Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader Slack](https://gocryptotrader.herokuapp.com/)
## HuobiHadax Exchange
### Current Features
+ REST functions
### How to enable
+ [Enable via configuration](https://github.com/thrasher-/gocryptotrader/tree/master/config#enable-exchange-via-config-example)
+ Individual package example below:
```go
// Exchanges will be abstracted out in further updates and examples will be
// supplied then
```
### How to do REST public/private calls
+ If enabled via "configuration".json file the exchange will be added to the
IBotExchange array in the ```go var bot Bot``` and you will only be able to use
the wrapper interface functions for accessing exchange data. View routines.go
for an example of integration usage with GoCryptoTrader. Rudimentary example
below:
main.go
```go
var h exchange.IBotExchange
for i := range bot.exchanges {
if bot.exchanges[i].GetName() == "HuobiHadax" {
h = bot.exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
tick, err := h.GetTickerPrice()
if err != nil {
// Handle error
}
// Fetches current orderbook information
ob, err := h.GetOrderbookEx()
if err != nil {
// Handle error
}
// Private calls - wrapper functions - make sure your APIKEY and APISECRET are
// set and AuthenticatedAPISupport is set to true
// Fetches current account information
accountInfo, err := h.GetExchangeAccountInfo()
if err != nil {
// Handle error
}
```
+ If enabled via individually importing package, rudimentary example below:
```go
// Public calls
// Fetches current ticker information
ticker, err := h.GetTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
ob, err := h.GetOrderBook()
if err != nil {
// Handle error
}
// Private calls - make sure your APIKEY and APISECRET are set and
// AuthenticatedAPISupport is set to true
// GetUserInfo returns account info
accountInfo, err := h.GetUserInfo(...)
if err != nil {
// Handle error
}
// Submits an order and the exchange and returns its tradeID
tradeID, err := h.Trade(...)
if err != nil {
// Handle error
}
```
### How to do LongPolling public/private calls
```go
// Exchanges will be abstracted out in further updates and examples will be
// supplied then
```
### Please click GoDocs chevron above to view current GoDoc information for this package
## Contribution
Please feel free to submit any pull requests or suggest any desired features to be added.
When submitting a PR, please abide by our coding guidelines:
+ Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting) guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)).
+ Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary) guidelines.
+ Code must adhere to our [coding style](https://github.com/thrasher-/gocryptotrader/blob/master/doc/coding_style.md).
+ Pull requests need to be based on and opened against the `master` branch.
## Donations
<img src="https://github.com/thrasher-/gocryptotrader/blob/master/web/src/assets/donate.png?raw=true" hspace="70">
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
***1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB***

View File

@@ -85,6 +85,7 @@ func (h *HUOBIHADAX) Setup(exch config.ExchangeConfig) {
h.SetAPIKeys(exch.APIKey, exch.APISecret, "", false)
h.APIAuthPEMKey = exch.APIAuthPEMKey
h.SetHTTPClientTimeout(exch.HTTPTimeout)
h.SetHTTPClientUserAgent(exch.HTTPUserAgent)
h.RESTPollingDelay = exch.RESTPollingDelay
h.Verbose = exch.Verbose
h.Websocket = exch.Websocket
@@ -755,7 +756,6 @@ func (h *HUOBIHADAX) SendAuthenticatedHTTPPostRequest(method, endpoint, postBody
method, endpoint, signatureParams.Encode())
headers := make(map[string]string)
headers["User-Agent"] = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36"
headers["Content-Type"] = "application/json"
headers["Accept-Language"] = "zh-cn"

View File

@@ -67,6 +67,7 @@ func (i *ItBit) Setup(exch config.ExchangeConfig) {
i.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
i.SetAPIKeys(exch.APIKey, exch.APISecret, exch.ClientID, false)
i.SetHTTPClientTimeout(exch.HTTPTimeout)
i.SetHTTPClientUserAgent(exch.HTTPUserAgent)
i.RESTPollingDelay = exch.RESTPollingDelay
i.Verbose = exch.Verbose
i.Websocket = exch.Websocket

View File

@@ -81,6 +81,7 @@ func (k *Kraken) Setup(exch config.ExchangeConfig) {
k.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
k.SetAPIKeys(exch.APIKey, exch.APISecret, "", false)
k.SetHTTPClientTimeout(exch.HTTPTimeout)
k.SetHTTPClientUserAgent(exch.HTTPUserAgent)
k.RESTPollingDelay = exch.RESTPollingDelay
k.Verbose = exch.Verbose
k.Websocket = exch.Websocket
@@ -111,40 +112,51 @@ func (k *Kraken) GetFee(cryptoTrade bool) float64 {
}
// GetServerTime returns current server time
func (k *Kraken) GetServerTime(unixTime bool) (interface{}, error) {
var result GeneralResponse
func (k *Kraken) GetServerTime() (TimeResponse, error) {
path := fmt.Sprintf("%s/%s/public/%s", krakenAPIURL, krakenAPIVersion, krakenServerTime)
err := k.SendHTTPRequest(path, &result)
if err != nil {
return nil, fmt.Errorf("getServerTime() error %s", err)
var response struct {
Error []string `json:"error"`
Result TimeResponse `json:"result"`
}
if unixTime {
return result.Result["unixtime"], nil
if err := k.SendHTTPRequest(path, &response); err != nil {
return response.Result, err
}
return result.Result["rfc1123"], nil
return response.Result, GetError(response.Error)
}
// GetAssets returns a full asset list
func (k *Kraken) GetAssets() (interface{}, error) {
var result GeneralResponse
func (k *Kraken) GetAssets() (map[string]Asset, error) {
path := fmt.Sprintf("%s/%s/public/%s", krakenAPIURL, krakenAPIVersion, krakenAssets)
return result.Result, k.SendHTTPRequest(path, &result)
var response struct {
Error []string `json:"error"`
Result map[string]Asset `json:"result"`
}
if err := k.SendHTTPRequest(path, &response); err != nil {
return response.Result, err
}
return response.Result, GetError(response.Error)
}
// GetAssetPairs returns a full asset pair list
func (k *Kraken) GetAssetPairs() (map[string]AssetPairs, error) {
type Response struct {
Result map[string]AssetPairs `json:"result"`
Error []interface{} `json:"error"`
}
response := Response{}
path := fmt.Sprintf("%s/%s/public/%s", krakenAPIURL, krakenAPIVersion, krakenAssetPairs)
return response.Result, k.SendHTTPRequest(path, &response)
var response struct {
Error []string `json:"error"`
Result map[string]AssetPairs `json:"result"`
}
if err := k.SendHTTPRequest(path, &response); err != nil {
return response.Result, err
}
return response.Result, GetError(response.Error)
}
// GetTicker returns ticker information from kraken
@@ -371,208 +383,422 @@ func (k *Kraken) GetSpread(symbol string) ([]Spread, error) {
}
// GetBalance returns your balance associated with your keys
func (k *Kraken) GetBalance() (interface{}, error) {
return k.SendAuthenticatedHTTPRequest(krakenBalance, url.Values{})
func (k *Kraken) GetBalance() (map[string]float64, error) {
var response struct {
Error []string `json:"error"`
Result map[string]string `json:"result"`
}
if err := k.SendAuthenticatedHTTPRequest(krakenBalance, url.Values{}, &response); err != nil {
return nil, err
}
result := make(map[string]float64)
for curency, balance := range response.Result {
var err error
if result[curency], err = strconv.ParseFloat(balance, 64); err != nil {
return nil, err
}
}
return result, GetError(response.Error)
}
// GetTradeBalance returns full information about your trades on Kraken
func (k *Kraken) GetTradeBalance(symbol, asset string) (interface{}, error) {
values := url.Values{}
func (k *Kraken) GetTradeBalance(args ...TradeBalanceOptions) (TradeBalanceInfo, error) {
params := url.Values{}
if args != nil {
if len(args[0].Aclass) != 0 {
params.Set("aclass", args[0].Aclass)
}
if len(args[0].Asset) != 0 {
params.Set("asset", args[0].Asset)
}
if len(symbol) > 0 {
values.Set("aclass", symbol)
}
if len(asset) > 0 {
values.Set("asset", asset)
}
return k.SendAuthenticatedHTTPRequest(krakenTradeBalance, values)
var response struct {
Error []string `json:"error"`
Result TradeBalanceInfo `json:"result"`
}
if err := k.SendAuthenticatedHTTPRequest(krakenTradeBalance, params, &response); err != nil {
return response.Result, err
}
return response.Result, GetError(response.Error)
}
// GetOpenOrders returns all current open orders
func (k *Kraken) GetOpenOrders(showTrades bool, userref int64) (interface{}, error) {
values := url.Values{}
func (k *Kraken) GetOpenOrders(args ...OrderInfoOptions) (OpenOrders, error) {
params := url.Values{}
if showTrades {
values.Set("trades", "true")
if args[0].Trades {
params.Set("trades", "true")
}
if userref != 0 {
values.Set("userref", strconv.FormatInt(userref, 10))
if args[0].UserRef != 0 {
params.Set("userref", strconv.FormatInt(int64(args[0].UserRef), 10))
}
return k.SendAuthenticatedHTTPRequest(krakenOpenOrders, values)
var response struct {
Error []string `json:"error"`
Result OpenOrders `json:"result"`
}
if err := k.SendAuthenticatedHTTPRequest(krakenOpenOrders, params, &response); err != nil {
return response.Result, err
}
return response.Result, GetError(response.Error)
}
// GetClosedOrders returns a list of closed orders
func (k *Kraken) GetClosedOrders(showTrades bool, userref, start, end, offset int64, closetime string) (interface{}, error) {
values := url.Values{}
func (k *Kraken) GetClosedOrders(args ...GetClosedOrdersOptions) (ClosedOrders, error) {
params := url.Values{}
if showTrades {
values.Set("trades", "true")
if args != nil {
if args[0].Trades {
params.Set("trades", "true")
}
if args[0].UserRef != 0 {
params.Set("userref", strconv.FormatInt(int64(args[0].UserRef), 10))
}
if len(args[0].Start) != 0 {
params.Set("start", args[0].Start)
}
if len(args[0].End) != 0 {
params.Set("end", args[0].End)
}
if args[0].Ofs != 0 {
params.Set("ofs", strconv.FormatInt(args[0].Ofs, 10))
}
if len(args[0].CloseTime) != 0 {
params.Set("closetime", args[0].CloseTime)
}
}
if userref != 0 {
values.Set("userref", strconv.FormatInt(userref, 10))
var response struct {
Error []string `json:"error"`
Result ClosedOrders `json:"result"`
}
if start != 0 {
values.Set("start", strconv.FormatInt(start, 10))
if err := k.SendAuthenticatedHTTPRequest(krakenClosedOrders, params, &response); err != nil {
return response.Result, err
}
if end != 0 {
values.Set("end", strconv.FormatInt(end, 10))
}
if offset != 0 {
values.Set("ofs", strconv.FormatInt(offset, 10))
}
if len(closetime) > 0 {
values.Set("closetime", closetime)
}
return k.SendAuthenticatedHTTPRequest(krakenClosedOrders, values)
return response.Result, GetError(response.Error)
}
// QueryOrdersInfo returns order information
func (k *Kraken) QueryOrdersInfo(showTrades bool, userref, txid int64) (interface{}, error) {
values := url.Values{}
if showTrades {
values.Set("trades", "true")
func (k *Kraken) QueryOrdersInfo(args OrderInfoOptions, txid string, txids ...string) (map[string]OrderInfo, error) {
params := url.Values{
"txid": {txid},
}
if userref != 0 {
values.Set("userref", strconv.FormatInt(userref, 10))
if txids != nil {
params.Set("txid", txid+","+strings.Join(txids, ","))
}
if txid != 0 {
values.Set("txid", strconv.FormatInt(userref, 10))
if args.Trades {
params.Set("trades", "true")
}
return k.SendAuthenticatedHTTPRequest(krakenQueryOrders, values)
if args.UserRef != 0 {
params.Set("userref", strconv.FormatInt(int64(args.UserRef), 10))
}
var response struct {
Error []string `json:"error"`
Result map[string]OrderInfo `json:"result"`
}
if err := k.SendAuthenticatedHTTPRequest(krakenQueryOrders, params, &response); err != nil {
return response.Result, err
}
return response.Result, GetError(response.Error)
}
// GetTradesHistory returns trade history information
func (k *Kraken) GetTradesHistory(tradeType string, showRelatedTrades bool, start, end, offset int64) (interface{}, error) {
values := url.Values{}
func (k *Kraken) GetTradesHistory(args ...GetTradesHistoryOptions) (TradesHistory, error) {
params := url.Values{}
if len(tradeType) > 0 {
values.Set("aclass", tradeType)
if args != nil {
if len(args[0].Type) != 0 {
params.Set("type", args[0].Type)
}
if args[0].Trades {
params.Set("trades", "true")
}
if len(args[0].Start) != 0 {
params.Set("start", args[0].Start)
}
if len(args[0].End) != 0 {
params.Set("end", args[0].End)
}
if args[0].Ofs != 0 {
params.Set("ofs", strconv.FormatInt(args[0].Ofs, 10))
}
}
if showRelatedTrades {
values.Set("trades", "true")
var response struct {
Error []string `json:"error"`
Result TradesHistory `json:"result"`
}
if start != 0 {
values.Set("start", strconv.FormatInt(start, 10))
if err := k.SendAuthenticatedHTTPRequest(krakenTradeHistory, params, &response); err != nil {
return response.Result, err
}
if end != 0 {
values.Set("end", strconv.FormatInt(end, 10))
}
if offset != 0 {
values.Set("offset", strconv.FormatInt(offset, 10))
}
return k.SendAuthenticatedHTTPRequest(krakenTradeHistory, values)
return response.Result, GetError(response.Error)
}
// QueryTrades returns information on a specific trade
func (k *Kraken) QueryTrades(txid int64, showRelatedTrades bool) (interface{}, error) {
values := url.Values{}
values.Set("txid", strconv.FormatInt(txid, 10))
if showRelatedTrades {
values.Set("trades", "true")
func (k *Kraken) QueryTrades(trades bool, txid string, txids ...string) (map[string]TradeInfo, error) {
params := url.Values{
"txid": {txid},
}
return k.SendAuthenticatedHTTPRequest(krakenQueryTrades, values)
if trades {
params.Set("trades", "true")
}
if txids != nil {
params.Set("txid", txid+","+strings.Join(txids, ","))
}
var response struct {
Error []string `json:"error"`
Result map[string]TradeInfo `json:"result"`
}
if err := k.SendAuthenticatedHTTPRequest(krakenQueryTrades, params, &response); err != nil {
return response.Result, err
}
return response.Result, GetError(response.Error)
}
// OpenPositions returns current open positions
func (k *Kraken) OpenPositions(txid int64, showPL bool) (interface{}, error) {
values := url.Values{}
values.Set("txid", strconv.FormatInt(txid, 10))
func (k *Kraken) OpenPositions(docalcs bool, txids ...string) (map[string]Position, error) {
params := url.Values{}
if showPL {
values.Set("docalcs", "true")
if txids != nil {
params.Set("txid", strings.Join(txids, ","))
}
return k.SendAuthenticatedHTTPRequest(krakenOpenPositions, values)
if docalcs {
params.Set("docalcs", "true")
}
var response struct {
Error []string `json:"error"`
Result map[string]Position `json:"result"`
}
if err := k.SendAuthenticatedHTTPRequest(krakenOpenPositions, params, &response); err != nil {
return response.Result, err
}
return response.Result, GetError(response.Error)
}
// GetLedgers returns current ledgers
func (k *Kraken) GetLedgers(symbol, asset, ledgerType string, start, end, offset int64) (interface{}, error) {
values := url.Values{}
func (k *Kraken) GetLedgers(args ...GetLedgersOptions) (Ledgers, error) {
params := url.Values{}
if len(symbol) > 0 {
values.Set("aclass", symbol)
if args != nil {
if len(args[0].Aclass) != 0 {
params.Set("aclass", args[0].Aclass)
}
if len(args[0].Asset) != 0 {
params.Set("asset", args[0].Asset)
}
if len(args[0].Type) != 0 {
params.Set("type", args[0].Type)
}
if len(args[0].Start) != 0 {
params.Set("start", args[0].Start)
}
if len(args[0].End) != 0 {
params.Set("end", args[0].End)
}
if args[0].Ofs != 0 {
params.Set("ofs", strconv.FormatInt(args[0].Ofs, 10))
}
}
if len(asset) > 0 {
values.Set("asset", asset)
var response struct {
Error []string `json:"error"`
Result Ledgers `json:"result"`
}
if len(ledgerType) > 0 {
values.Set("type", ledgerType)
if err := k.SendAuthenticatedHTTPRequest(krakenLedgers, params, &response); err != nil {
return response.Result, err
}
if start != 0 {
values.Set("start", strconv.FormatInt(start, 10))
}
if end != 0 {
values.Set("end", strconv.FormatInt(end, 10))
}
if offset != 0 {
values.Set("offset", strconv.FormatInt(offset, 10))
}
return k.SendAuthenticatedHTTPRequest(krakenLedgers, values)
return response.Result, GetError(response.Error)
}
// QueryLedgers queries an individual ledger by ID
func (k *Kraken) QueryLedgers(id string) (interface{}, error) {
values := url.Values{}
values.Set("id", id)
func (k *Kraken) QueryLedgers(id string, ids ...string) (map[string]LedgerInfo, error) {
params := url.Values{
"id": {id},
}
return k.SendAuthenticatedHTTPRequest(krakenQueryLedgers, values)
if ids != nil {
params.Set("id", id+","+strings.Join(ids, ","))
}
var response struct {
Error []string `json:"error"`
Result map[string]LedgerInfo `json:"result"`
}
if err := k.SendAuthenticatedHTTPRequest(krakenQueryLedgers, params, &response); err != nil {
return response.Result, err
}
return response.Result, GetError(response.Error)
}
// GetTradeVolume returns your trade volume by currency
func (k *Kraken) GetTradeVolume(symbol string) (interface{}, error) {
values := url.Values{}
values.Set("pair", symbol)
func (k *Kraken) GetTradeVolume(feeinfo bool, symbol ...string) (TradeVolumeResponse, error) {
params := url.Values{}
return k.SendAuthenticatedHTTPRequest(krakenTradeVolume, values)
if symbol != nil {
params.Set("pair", strings.Join(symbol, ","))
}
if feeinfo {
params.Set("fee-info", "true")
}
var response struct {
Error []string `json:"error"`
Result TradeVolumeResponse `json:"result"`
}
if err := k.SendAuthenticatedHTTPRequest(krakenTradeVolume, params, &response); err != nil {
return response.Result, err
}
return response.Result, GetError(response.Error)
}
// AddOrder adds a new order for Kraken exchange
func (k *Kraken) AddOrder(symbol, side, orderType string, price, price2, volume, leverage, position float64) (interface{}, error) {
values := url.Values{}
values.Set("pairs", symbol)
values.Set("type", side)
values.Set("ordertype", orderType)
values.Set("price", strconv.FormatFloat(price, 'f', -1, 64))
values.Set("price2", strconv.FormatFloat(price, 'f', -1, 64))
values.Set("volume", strconv.FormatFloat(volume, 'f', -1, 64))
values.Set("leverage", strconv.FormatFloat(leverage, 'f', -1, 64))
values.Set("position", strconv.FormatFloat(position, 'f', -1, 64))
func (k *Kraken) AddOrder(symbol, side, orderType string, volume, price, price2, leverage float64, args AddOrderOptions) (AddOrderResponse, error) {
params := url.Values{
"pair": {symbol},
"type": {side},
"ordertype": {orderType},
"volume": {strconv.FormatFloat(volume, 'f', -1, 64)},
}
return k.SendAuthenticatedHTTPRequest(krakenOrderPlace, values)
if price != 0 {
params.Set("price", strconv.FormatFloat(price, 'f', -1, 64))
}
if price2 != 0 {
params.Set("price2", strconv.FormatFloat(price2, 'f', -1, 64))
}
if leverage != 0 {
params.Set("leverage", strconv.FormatFloat(leverage, 'f', -1, 64))
}
if len(args.Oflags) != 0 {
params.Set("oflags", args.Oflags)
}
if len(args.StartTm) != 0 {
params.Set("starttm", args.StartTm)
}
if len(args.ExpireTm) != 0 {
params.Set("expiretm", args.ExpireTm)
}
if len(args.CloseOrderType) != 0 {
params.Set("close[ordertype]", args.ExpireTm)
}
if args.ClosePrice != 0 {
params.Set("close[price]", strconv.FormatFloat(args.ClosePrice, 'f', -1, 64))
}
if args.ClosePrice2 != 0 {
params.Set("close[price2]", strconv.FormatFloat(args.ClosePrice2, 'f', -1, 64))
}
if args.Validate {
params.Set("validate", "true")
}
var response struct {
Error []string `json:"error"`
Result AddOrderResponse `json:"result"`
}
if err := k.SendAuthenticatedHTTPRequest(krakenOrderPlace, params, &response); err != nil {
return response.Result, err
}
return response.Result, GetError(response.Error)
}
// CancelOrder cancels order by orderID
func (k *Kraken) CancelOrder(orderID int64) (interface{}, error) {
values := url.Values{}
values.Set("txid", strconv.FormatInt(orderID, 10))
func (k *Kraken) CancelOrder(txid string) (CancelOrderResponse, error) {
values := url.Values{
"txid": {txid},
}
return k.SendAuthenticatedHTTPRequest(krakenOrderCancel, values)
var response struct {
Error []string `json:"error"`
Result CancelOrderResponse `json:"result"`
}
if err := k.SendAuthenticatedHTTPRequest(krakenOrderCancel, values, &response); err != nil {
return response.Result, err
}
return response.Result, GetError(response.Error)
}
// GetError parse Exchange errors in response and return the first one
// Error format from API doc:
// error = array of error messages in the format of:
// <char-severity code><string-error category>:<string-error type>[:<string-extra info>]
// severity code can be E for error or W for warning
func GetError(errors []string) error {
for _, e := range errors {
switch e[0] {
case 'W':
log.Printf("Kraken API warning: %v\n", e[1:])
default:
return fmt.Errorf("Kraken API error: %v", e[1:])
}
}
return nil
}
// SendHTTPRequest sends an unauthenticated HTTP requests
@@ -581,9 +807,9 @@ func (k *Kraken) SendHTTPRequest(path string, result interface{}) error {
}
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request
func (k *Kraken) SendAuthenticatedHTTPRequest(method string, values url.Values) (interface{}, error) {
func (k *Kraken) SendAuthenticatedHTTPRequest(method string, params url.Values, result interface{}) (err error) {
if !k.AuthenticatedAPISupport {
return nil, fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, k.Name)
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, k.Name)
}
path := fmt.Sprintf("/%s/private/%s", krakenAPIVersion, method)
@@ -593,35 +819,24 @@ func (k *Kraken) SendAuthenticatedHTTPRequest(method string, values url.Values)
k.Nonce.Inc()
}
values.Set("nonce", k.Nonce.String())
params.Set("nonce", k.Nonce.String())
secret, err := common.Base64Decode(k.APISecret)
if err != nil {
return nil, err
return err
}
shasum := common.GetSHA256([]byte(values.Get("nonce") + values.Encode()))
encoded := params.Encode()
shasum := common.GetSHA256([]byte(params.Get("nonce") + encoded))
signature := common.Base64Encode(common.GetHMAC(common.HashSHA512, append([]byte(path), shasum...), secret))
if k.Verbose {
log.Printf("Sending POST request to %s, path: %s.", krakenAPIURL, path)
log.Printf("Sending POST request to %s, path: %s, params: %s", krakenAPIURL, path, encoded)
}
headers := make(map[string]string)
headers["API-Key"] = k.APIKey
headers["API-Sign"] = signature
var resp interface{}
err = k.SendPayload("POST", krakenAPIURL+path, headers, strings.NewReader(values.Encode()), &resp, true, k.Verbose)
if err != nil {
return resp, err
}
data := resp.(map[string]interface{})
if len(data["error"].([]interface{})) != 0 {
return nil, fmt.Errorf("kraken AuthenticattedHTTPRequest error: %s", data["error"])
}
return data["result"].(interface{}), nil
return k.SendPayload("POST", krakenAPIURL+path, headers, strings.NewReader(encoded), result, true, k.Verbose)
}

View File

@@ -47,11 +47,7 @@ func TestGetFee(t *testing.T) {
func TestGetServerTime(t *testing.T) {
t.Parallel()
_, err := k.GetServerTime(false)
if err != nil {
t.Error("Test Failed - GetServerTime() error", err)
}
_, err = k.GetServerTime(true)
_, err := k.GetServerTime()
if err != nil {
t.Error("Test Failed - GetServerTime() error", err)
}
@@ -123,7 +119,8 @@ func TestGetBalance(t *testing.T) {
func TestGetTradeBalance(t *testing.T) {
t.Parallel()
_, err := k.GetTradeBalance("", "")
args := TradeBalanceOptions{Asset: "ZEUR"}
_, err := k.GetTradeBalance(args)
if err == nil {
t.Error("Test Failed - GetTradeBalance() error", err)
}
@@ -131,7 +128,8 @@ func TestGetTradeBalance(t *testing.T) {
func TestGetOpenOrders(t *testing.T) {
t.Parallel()
_, err := k.GetOpenOrders(true, 0)
args := OrderInfoOptions{Trades: true}
_, err := k.GetOpenOrders(args)
if err == nil {
t.Error("Test Failed - GetOpenOrders() error", err)
}
@@ -139,7 +137,8 @@ func TestGetOpenOrders(t *testing.T) {
func TestGetClosedOrders(t *testing.T) {
t.Parallel()
_, err := k.GetClosedOrders(true, 0, 0, 0, 0, "")
args := GetClosedOrdersOptions{Trades: true, Start: "OE4KV4-4FVQ5-V7XGPU"}
_, err := k.GetClosedOrders(args)
if err == nil {
t.Error("Test Failed - GetClosedOrders() error", err)
}
@@ -147,7 +146,8 @@ func TestGetClosedOrders(t *testing.T) {
func TestQueryOrdersInfo(t *testing.T) {
t.Parallel()
_, err := k.QueryOrdersInfo(false, 0, 0)
args := OrderInfoOptions{Trades: true}
_, err := k.QueryOrdersInfo(args, "OR6ZFV-AA6TT-CKFFIW", "OAMUAJ-HLVKG-D3QJ5F")
if err == nil {
t.Error("Test Failed - QueryOrdersInfo() error", err)
}
@@ -155,7 +155,8 @@ func TestQueryOrdersInfo(t *testing.T) {
func TestGetTradesHistory(t *testing.T) {
t.Parallel()
_, err := k.GetTradesHistory("", false, 0, 0, 0)
args := GetTradesHistoryOptions{Trades: true, Start: "TMZEDR-VBJN2-NGY6DX", End: "TVRXG2-R62VE-RWP3UW"}
_, err := k.GetTradesHistory(args)
if err == nil {
t.Error("Test Failed - GetTradesHistory() error", err)
}
@@ -163,7 +164,7 @@ func TestGetTradesHistory(t *testing.T) {
func TestQueryTrades(t *testing.T) {
t.Parallel()
_, err := k.QueryTrades(0, false)
_, err := k.QueryTrades(true, "TMZEDR-VBJN2-NGY6DX", "TFLWIB-KTT7L-4TWR3L", "TDVRAH-2H6OS-SLSXRX")
if err == nil {
t.Error("Test Failed - QueryTrades() error", err)
}
@@ -171,7 +172,7 @@ func TestQueryTrades(t *testing.T) {
func TestOpenPositions(t *testing.T) {
t.Parallel()
_, err := k.OpenPositions(0, false)
_, err := k.OpenPositions(false)
if err == nil {
t.Error("Test Failed - OpenPositions() error", err)
}
@@ -179,7 +180,8 @@ func TestOpenPositions(t *testing.T) {
func TestGetLedgers(t *testing.T) {
t.Parallel()
_, err := k.GetLedgers("bla", "bla", "bla", 0, 0, 0)
args := GetLedgersOptions{Start: "LRUHXI-IWECY-K4JYGO", End: "L5NIY7-JZQJD-3J4M2V", Ofs: 15}
_, err := k.GetLedgers(args)
if err == nil {
t.Error("Test Failed - GetLedgers() error", err)
}
@@ -187,7 +189,7 @@ func TestGetLedgers(t *testing.T) {
func TestQueryLedgers(t *testing.T) {
t.Parallel()
_, err := k.QueryLedgers("1337")
_, err := k.QueryLedgers("LVTSFS-NHZVM-EXNZ5M")
if err == nil {
t.Error("Test Failed - QueryLedgers() error", err)
}
@@ -195,7 +197,7 @@ func TestQueryLedgers(t *testing.T) {
func TestGetTradeVolume(t *testing.T) {
t.Parallel()
_, err := k.GetTradeVolume("BCHEUR")
_, err := k.GetTradeVolume(true, "OAVY7T-MV5VK-KHDF5X")
if err == nil {
t.Error("Test Failed - GetTradeVolume() error", err)
}
@@ -203,7 +205,8 @@ func TestGetTradeVolume(t *testing.T) {
func TestAddOrder(t *testing.T) {
t.Parallel()
_, err := k.AddOrder("bla", "bla", "bla", 0, 0, 0, 0, 0)
args := AddOrderOptions{Oflags: "fcib"}
_, err := k.AddOrder("XXBTZUSD", "sell", "market", 0.00000001, 0, 0, 0, args)
if err == nil {
t.Error("Test Failed - AddOrder() error", err)
}
@@ -211,7 +214,7 @@ func TestAddOrder(t *testing.T) {
func TestCancelOrder(t *testing.T) {
t.Parallel()
_, err := k.CancelOrder(1337)
_, err := k.CancelOrder("OAVY7T-MV5VK-KHDF5X")
if err == nil {
t.Error("Test Failed - CancelOrder() error", err)
}

View File

@@ -1,9 +1,17 @@
package kraken
// GeneralResponse is a generalized response type
type GeneralResponse struct {
Result map[string]interface{} `json:"result"`
Error []interface{} `json:"error"`
// TimeResponse type
type TimeResponse struct {
Unixtime int64 `json:"unixtime"`
Rfc1123 string `json:"rfc1123"`
}
// Asset holds asset information
type Asset struct {
Altname string `json:"altname"`
AclassBase string `json:"aclass_base"`
Decimals int `json:"decimals"`
DisplayDecimals int `json:"display_decimals"`
}
// AssetPairs holds asset pair information
@@ -92,3 +100,211 @@ type Spread struct {
Bid float64
Ask float64
}
// TradeBalanceOptions type
type TradeBalanceOptions struct {
Aclass string
Asset string
}
// TradeBalanceInfo type
type TradeBalanceInfo struct {
EquivalentBalance float64 `json:"eb,string"` // combined balance of all currencies
TradeBalance float64 `json:"tb,string"` // combined balance of all equity currencies
MarginAmount float64 `json:"m,string"` // margin amount of open positions
Net float64 `json:"n,string"` // unrealized net profit/loss of open positions
Equity float64 `json:"e,string"` // trade balance + unrealized net profit/loss
FreeMargin float64 `json:"mf,string"` // equity - initial margin (maximum margin available to open new positions)
MarginLevel float64 `json:"ml,string"` // (equity / initial margin) * 100
}
// OrderInfo type
type OrderInfo struct {
RefID string `json:"refid"`
UserRef int32 `json:"userref"`
Status string `json:"status"`
OpenTm float64 `json:"opentm"`
StartTm float64 `json:"starttm"`
ExpireTm float64 `json:"expiretm"`
Descr struct {
Pair string `json:"pair"`
Type string `json:"type"`
OrderType string `json:"ordertype"`
Price float64 `json:"price,string"`
Price2 float64 `json:"price2,string"`
Leverage string `json:"leverage"`
Order string `json:"order"`
Close string `json:"close"`
} `json:"descr"`
Vol float64 `json:"vol,string"`
VolExec float64 `json:"vol_exec,string"`
Cost float64 `json:"cost,string"`
Fee float64 `json:"fee,string"`
Price float64 `json:"price,string"`
StopPrice float64 `json:"stopprice,string"`
LimitPrice float64 `json:"limitprice,string"`
Misc string `json:"misc"`
Oflags string `json:"oflags"`
Trades []string `json:"trades"`
}
// OpenOrders type
type OpenOrders struct {
Open map[string]OrderInfo `json:"open"`
Count int64 `json:"count"`
}
// ClosedOrders type
type ClosedOrders struct {
Closed map[string]OrderInfo `json:"closed"`
Count int64 `json:"count"`
}
// GetClosedOrdersOptions type
type GetClosedOrdersOptions struct {
Trades bool
UserRef int32
Start string
End string
Ofs int64
CloseTime string
}
// OrderInfoOptions type
type OrderInfoOptions struct {
Trades bool
UserRef int32
}
// GetTradesHistoryOptions type
type GetTradesHistoryOptions struct {
Type string
Trades bool
Start string
End string
Ofs int64
}
// TradesHistory type
type TradesHistory struct {
Trades map[string]TradeInfo `json:"trades"`
Count int64 `json:"count"`
}
// TradeInfo type
type TradeInfo struct {
OrderTxID string `json:"ordertxid"`
Pair string `json:"pair"`
Time float64 `json:"time"`
Type string `json:"type"`
OrderType string `json:"ordertype"`
Price float64 `json:"price,string"`
Cost float64 `json:"cost,string"`
Fee float64 `json:"fee,string"`
Vol float64 `json:"vol,string"`
Margin float64 `json:"margin,string"`
Misc string `json:"misc"`
PosTxID string `json:"postxid"`
Cprice float64 `json:"cprice,string"`
Cfee float64 `json:"cfee,string"`
Cvol float64 `json:"cvol,string"`
Cmargin float64 `json:"cmargin,string"`
Trades []string `json:"trades"`
PosStatus string `json:"posstatus"`
}
// Position holds the opened position
type Position struct {
Ordertxid string `json:"ordertxid"`
Pair string `json:"pair"`
Time float64 `json:"time"`
Type string `json:"type"`
OrderType string `json:"ordertype"`
Cost float64 `json:"cost,string"`
Fee float64 `json:"fee,string"`
Vol float64 `json:"vol,string"`
VolClosed float64 `json:"vol_closed,string"`
Margin float64 `json:"margin,string"`
Rollovertm int64 `json:"rollovertm,string"`
Misc string `json:"misc"`
Oflags string `json:"oflags"`
PosStatus string `json:"posstatus"`
Net string `json:"net"`
Terms string `json:"terms"`
}
// GetLedgersOptions type
type GetLedgersOptions struct {
Aclass string
Asset string
Type string
Start string
End string
Ofs int64
}
// Ledgers type
type Ledgers struct {
Ledger map[string]LedgerInfo `json:"ledger"`
Count int64 `json:"count"`
}
// LedgerInfo type
type LedgerInfo struct {
Refid string `json:"refid"`
Time float64 `json:"time"`
Type string `json:"type"`
Aclass string `json:"aclass"`
Asset string `json:"asset"`
Amount float64 `json:"amount,string"`
Fee float64 `json:"fee,string"`
Balance float64 `json:"balance,string"`
}
// TradeVolumeResponse type
type TradeVolumeResponse struct {
Currency string `json:"currency"`
Volume float64 `json:"volume,string"`
Fees map[string]TradeVolumeFee `json:"fees"`
FeesMaker map[string]TradeVolumeFee `json:"fees_maker"`
}
// TradeVolumeFee type
type TradeVolumeFee struct {
Fee float64 `json:"fee,string"`
MinFee float64 `json:"minfee,string"`
MaxFee float64 `json:"maxfee,string"`
NextFee float64 `json:"nextfee,string"`
NextVolume float64 `json:"nextvolume,string"`
TierVolume float64 `json:"tiervolume,string"`
}
// AddOrderResponse type
type AddOrderResponse struct {
Description OrderDescription `json:"descr"`
TransactionIds []string `json:"txid"`
}
// OrderDescription represents an orders description
type OrderDescription struct {
Close string `json:"close"`
Order string `json:"order"`
}
// AddOrderOptions represents the AddOrder options
type AddOrderOptions struct {
UserRef int32
Oflags string
StartTm string
ExpireTm string
CloseOrderType string
ClosePrice float64
ClosePrice2 float64
Validate bool
}
// CancelOrderResponse type
type CancelOrderResponse struct {
Count int64 `json:"count"`
Pending interface{} `json:"pending"`
}

View File

@@ -68,6 +68,7 @@ func (l *LakeBTC) Setup(exch config.ExchangeConfig) {
l.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
l.SetAPIKeys(exch.APIKey, exch.APISecret, "", false)
l.SetHTTPClientTimeout(exch.HTTPTimeout)
l.SetHTTPClientUserAgent(exch.HTTPUserAgent)
l.RESTPollingDelay = exch.RESTPollingDelay
l.Verbose = exch.Verbose
l.Websocket = exch.Websocket

View File

@@ -73,6 +73,7 @@ func (l *Liqui) Setup(exch config.ExchangeConfig) {
l.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
l.SetAPIKeys(exch.APIKey, exch.APISecret, "", false)
l.SetHTTPClientTimeout(exch.HTTPTimeout)
l.SetHTTPClientUserAgent(exch.HTTPUserAgent)
l.RESTPollingDelay = exch.RESTPollingDelay
l.Verbose = exch.Verbose
l.Websocket = exch.Websocket

View File

@@ -136,6 +136,7 @@ func (l *LocalBitcoins) Setup(exch config.ExchangeConfig) {
l.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
l.SetAPIKeys(exch.APIKey, exch.APISecret, "", false)
l.SetHTTPClientTimeout(exch.HTTPTimeout)
l.SetHTTPClientUserAgent(exch.HTTPUserAgent)
l.RESTPollingDelay = exch.RESTPollingDelay
l.Verbose = exch.Verbose
l.Websocket = exch.Websocket
@@ -341,37 +342,57 @@ func (l *LocalBitcoins) GetCurrencies() error {
// view contacts where the token owner is either buying or selling, respectively.
// E.g. /api/dashboard/buyer/. All contacts where the token owner is
// participating are returned.
func (l *LocalBitcoins) GetDashboardInfo() (DashBoardInfo, error) {
resp := DashBoardInfo{}
func (l *LocalBitcoins) GetDashboardInfo() ([]DashBoardInfo, error) {
var resp struct {
Data struct {
ContactList []DashBoardInfo `json:"contact_list"`
ContactCount int `json:"contact_count"`
}
}
return resp,
return resp.Data.ContactList,
l.SendAuthenticatedHTTPRequest("GET", localbitcoinsAPIDashboard, nil, &resp)
}
// GetDashboardReleasedTrades returns a list of all released trades where the
// token owner is either a buyer or seller.
func (l *LocalBitcoins) GetDashboardReleasedTrades() (DashBoardInfo, error) {
resp := DashBoardInfo{}
func (l *LocalBitcoins) GetDashboardReleasedTrades() ([]DashBoardInfo, error) {
var resp struct {
Data struct {
ContactList []DashBoardInfo `json:"contact_list"`
ContactCount int `json:"contact_count"`
}
}
return resp,
return resp.Data.ContactList,
l.SendAuthenticatedHTTPRequest("GET", localbitcoinsAPIDashboardReleased, nil, &resp)
}
// GetDashboardCancelledTrades returns a list of all canceled trades where the
// token owner is either a buyer or seller.
func (l *LocalBitcoins) GetDashboardCancelledTrades() (DashBoardInfo, error) {
resp := DashBoardInfo{}
func (l *LocalBitcoins) GetDashboardCancelledTrades() ([]DashBoardInfo, error) {
var resp struct {
Data struct {
ContactList []DashBoardInfo `json:"contact_list"`
ContactCount int `json:"contact_count"`
}
}
return resp,
return resp.Data.ContactList,
l.SendAuthenticatedHTTPRequest("GET", localbitcoinsAPIDashboardCancelled, nil, &resp)
}
// GetDashboardClosedTrades returns a list of all closed trades where the token
// owner is either a buyer or seller.
func (l *LocalBitcoins) GetDashboardClosedTrades() (DashBoardInfo, error) {
resp := DashBoardInfo{}
func (l *LocalBitcoins) GetDashboardClosedTrades() ([]DashBoardInfo, error) {
var resp struct {
Data struct {
ContactList []DashBoardInfo `json:"contact_list"`
ContactCount int `json:"contact_count"`
}
}
return resp,
return resp.Data.ContactList,
l.SendAuthenticatedHTTPRequest("GET", localbitcoinsAPIDashboardClosed, nil, &resp)
}

View File

@@ -189,7 +189,7 @@ type DashBoardInfo struct {
Buyer struct {
Username string `json:"username"`
TradeCount string `json:"trade_count"`
FeedbackScore string `json:"feedback_score"`
FeedbackScore int `json:"feedback_score"`
Name string `json:"name"`
LastOnline string `json:"last_online"`
RealName string `json:"real_name"`
@@ -200,7 +200,7 @@ type DashBoardInfo struct {
Seller struct {
Username string `json:"username"`
TradeCount string `json:"trade_count"`
FeedbackScore string `json:"feedback_score"`
FeedbackScore int `json:"feedback_score"`
Name string `json:"name"`
LastOnline string `json:"last_online"`
} `json:"seller"`
@@ -216,7 +216,7 @@ type DashBoardInfo struct {
Advertiser struct {
Username string `json:"username"`
TradeCount string `json:"trade_count"`
FeedbackScore string `json:"feedback_score"`
FeedbackScore int `json:"feedback_score"`
Name string `json:"name"`
LastOnline string `json:"last_online"`
} `json:"advertiser"`

View File

@@ -132,6 +132,7 @@ func (o *OKCoin) Setup(exch config.ExchangeConfig) {
o.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
o.SetAPIKeys(exch.APIKey, exch.APISecret, "", false)
o.SetHTTPClientTimeout(exch.HTTPTimeout)
o.SetHTTPClientUserAgent(exch.HTTPUserAgent)
o.RESTPollingDelay = exch.RESTPollingDelay
o.Verbose = exch.Verbose
o.Websocket = exch.Websocket

View File

@@ -120,6 +120,7 @@ func (o *OKEX) Setup(exch config.ExchangeConfig) {
o.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
o.SetAPIKeys(exch.APIKey, exch.APISecret, exch.ClientID, false)
o.SetHTTPClientTimeout(exch.HTTPTimeout)
o.SetHTTPClientUserAgent(exch.HTTPUserAgent)
o.RESTPollingDelay = exch.RESTPollingDelay
o.Verbose = exch.Verbose
o.Websocket = exch.Websocket

View File

@@ -84,6 +84,7 @@ func (p *Poloniex) Setup(exch config.ExchangeConfig) {
p.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
p.SetAPIKeys(exch.APIKey, exch.APISecret, "", false)
p.SetHTTPClientTimeout(exch.HTTPTimeout)
p.SetHTTPClientUserAgent(exch.HTTPUserAgent)
p.RESTPollingDelay = exch.RESTPollingDelay
p.Verbose = exch.Verbose
p.Websocket = exch.Websocket

View File

@@ -25,6 +25,7 @@ type Requester struct {
UnauthLimit *RateLimit
AuthLimit *RateLimit
Name string
UserAgent string
Cycle time.Time
m sync.Mutex
Jobs chan Job
@@ -230,6 +231,10 @@ func (r *Requester) checkRequest(method, path string, body io.Reader, headers ma
req.Header.Add(k, v)
}
if r.UserAgent != "" && req.Header.Get("User-Agent") == "" {
req.Header.Add("User-Agent", r.UserAgent)
}
return req, nil
}
@@ -245,7 +250,6 @@ func (r *Requester) DoRequest(req *http.Request, method, path string, headers ma
if r.RequiresRateLimiter() {
r.DecrementRequests(authRequest)
}
return err
}
if resp == nil {

View File

@@ -76,6 +76,7 @@ func (w *WEX) Setup(exch config.ExchangeConfig) {
w.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
w.SetAPIKeys(exch.APIKey, exch.APISecret, "", false)
w.SetHTTPClientTimeout(exch.HTTPTimeout)
w.SetHTTPClientUserAgent(exch.HTTPUserAgent)
w.RESTPollingDelay = exch.RESTPollingDelay
w.Verbose = exch.Verbose
w.Websocket = exch.Websocket

View File

@@ -82,6 +82,7 @@ func (y *Yobit) Setup(exch config.ExchangeConfig) {
y.AvailablePairs = common.SplitStrings(exch.AvailablePairs, ",")
y.EnabledPairs = common.SplitStrings(exch.EnabledPairs, ",")
y.SetHTTPClientTimeout(exch.HTTPTimeout)
y.SetHTTPClientUserAgent(exch.HTTPUserAgent)
err := y.SetCurrencyPairFormat()
if err != nil {
log.Fatal(err)

View File

@@ -1,9 +1,140 @@
# GoCryptoTrader package zb
# GoCryptoTrader package Zb
<img src="https://github.com/thrasher-/gocryptotrader/blob/master/web/src/assets/page-logo.png?raw=true" width="350px" height="350px" hspace="70">
[![Build Status](https://travis-ci.org/thrasher-/gocryptotrader.svg?branch=master)](https://travis-ci.org/thrasher-/gocryptotrader)
[![Software License](https://img.shields.io/badge/License-MIT-orange.svg?style=flat-square)](https://github.com/thrasher-/gocryptotrader/blob/master/LICENSE)
[![GoDoc](https://godoc.org/github.com/thrasher-/gocryptotrader?status.svg)](https://godoc.org/github.com/thrasher-/gocryptotrader/exchanges/zb)
[![Coverage Status](http://codecov.io/github/thrasher-/gocryptotrader/coverage.svg?branch=master)](http://codecov.io/github/thrasher-/gocryptotrader?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/thrasher-/gocryptotrader)](https://goreportcard.com/report/github.com/thrasher-/gocryptotrader)
This zb package is part of the GoCryptoTrader codebase.
## ZB Exchange
## This is still in active development
You can track ideas, planned features and what's in progresss on this Trello board: [https://trello.com/b/ZAhMhpOy/gocryptotrader](https://trello.com/b/ZAhMhpOy/gocryptotrader).
Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader Slack](https://gocryptotrader.herokuapp.com/)
## ZB Exchange
### Current Features
ZB 交易所的支持支持获取K线、买/卖订单、取消订单
+ REST functions
### How to enable
+ [Enable via configuration](https://github.com/thrasher-/gocryptotrader/tree/master/config#enable-exchange-via-config-example)
+ Individual package example below:
```go
// Exchanges will be abstracted out in further updates and examples will be
// supplied then
```
### How to do REST public/private calls
+ If enabled via "configuration".json file the exchange will be added to the
IBotExchange array in the ```go var bot Bot``` and you will only be able to use
the wrapper interface functions for accessing exchange data. View routines.go
for an example of integration usage with GoCryptoTrader. Rudimentary example
below:
main.go
```go
var z exchange.IBotExchange
for i := range bot.exchanges {
if bot.exchanges[i].GetName() == "ZB" {
z = bot.exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
tick, err := z.GetTickerPrice()
if err != nil {
// Handle error
}
// Fetches current orderbook information
ob, err := z.GetOrderbookEx()
if err != nil {
// Handle error
}
// Private calls - wrapper functions - make sure your APIKEY and APISECRET are
// set and AuthenticatedAPISupport is set to true
// Fetches current account information
accountInfo, err := z.GetExchangeAccountInfo()
if err != nil {
// Handle error
}
```
+ If enabled via individually importing package, rudimentary example below:
```go
// Public calls
// Fetches current ticker information
ticker, err := z.GetTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
ob, err := z.GetOrderBook()
if err != nil {
// Handle error
}
// Private calls - make sure your APIKEY and APISECRET are set and
// AuthenticatedAPISupport is set to true
// GetUserInfo returns account info
accountInfo, err := z.GetUserInfo(...)
if err != nil {
// Handle error
}
// Submits an order and the exchange and returns its tradeID
tradeID, err := z.Trade(...)
if err != nil {
// Handle error
}
```
### How to do LongPolling public/private calls
```go
// Exchanges will be abstracted out in further updates and examples will be
// supplied then
```
### Please click GoDocs chevron above to view current GoDoc information for this package
## Contribution
Please feel free to submit any pull requests or suggest any desired features to be added.
When submitting a PR, please abide by our coding guidelines:
+ Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting) guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)).
+ Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary) guidelines.
+ Code must adhere to our [coding style](https://github.com/thrasher-/gocryptotrader/blob/master/doc/coding_style.md).
+ Pull requests need to be based on and opened against the `master` branch.
## Donations
<img src="https://github.com/thrasher-/gocryptotrader/blob/master/web/src/assets/donate.png?raw=true" hspace="70">
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
***1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB***

View File

@@ -70,6 +70,7 @@ func (z *ZB) Setup(exch config.ExchangeConfig) {
z.SetAPIKeys(exch.APIKey, exch.APISecret, "", false)
z.APIAuthPEMKey = exch.APIAuthPEMKey
z.SetHTTPClientTimeout(exch.HTTPTimeout)
z.SetHTTPClientUserAgent(exch.HTTPUserAgent)
z.RESTPollingDelay = exch.RESTPollingDelay
z.Verbose = exch.Verbose
z.Websocket = exch.Websocket
@@ -303,9 +304,6 @@ func (z *ZB) SendAuthenticatedHTTPRequest(method, endpoint string, values url.Va
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, z.Name)
}
headers := make(map[string]string)
headers["User-Agent"] = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36"
mapParams2Sign := url.Values{}
mapParams2Sign.Set("accesskey", z.APIKey)
mapParams2Sign.Set("method", values.Get("method"))
@@ -314,5 +312,5 @@ func (z *ZB) SendAuthenticatedHTTPRequest(method, endpoint string, values url.Va
url := fmt.Sprintf("%s/%s?%s", zbMarketURL, endpoint, values.Encode())
return z.SendPayload(method, url, headers, strings.NewReader(""), result, true, z.Verbose)
return z.SendPayload(method, url, nil, strings.NewReader(""), result, true, z.Verbose)
}

1815
testdata/configtest.json vendored

File diff suppressed because one or more lines are too long

View File

@@ -52,6 +52,7 @@ const (
bitfinex = "..%s..%sexchanges%sbitfinex%s"
bitflyer = "..%s..%sexchanges%sbitflyer%s"
bithumb = "..%s..%sexchanges%sbithumb%s"
bitmex = "..%s..%sexchanges%sbitmex%s"
bitstamp = "..%s..%sexchanges%sbitstamp%s"
bittrex = "..%s..%sexchanges%sbittrex%s"
btcc = "..%s..%sexchanges%sbtcc%s"
@@ -59,9 +60,11 @@ const (
coinbasepro = "..%s..%sexchanges%scoinbasepro%s"
coinut = "..%s..%sexchanges%scoinut%s"
exmo = "..%s..%sexchanges%sexmo%s"
gateio = "..%s..%sexchanges%sgateio%s"
gemini = "..%s..%sexchanges%sgemini%s"
hitbtc = "..%s..%sexchanges%shitbtc%s"
huobi = "..%s..%sexchanges%shuobi%s"
huobihadax = "..%s..%sexchanges%shuobihadax%s"
itbit = "..%s..%sexchanges%sitbit%s"
kraken = "..%s..%sexchanges%skraken%s"
lakebtc = "..%s..%sexchanges%slakebtc%s"
@@ -72,6 +75,7 @@ const (
poloniex = "..%s..%sexchanges%spoloniex%s"
wex = "..%s..%sexchanges%swex%s"
yobit = "..%s..%sexchanges%syobit%s"
zb = "..%s..%sexchanges%szb%s"
contributorsList = "https://api.github.com/repos/thrasher-/gocryptotrader/contributors"
@@ -223,6 +227,7 @@ func addPaths() {
codebasePaths["exchanges bitfinex"] = fmt.Sprintf(bitfinex, path, path, path, path)
codebasePaths["exchanges bitflyer"] = fmt.Sprintf(bitflyer, path, path, path, path)
codebasePaths["exchanges bithumb"] = fmt.Sprintf(bithumb, path, path, path, path)
codebasePaths["exchanges bitmex"] = fmt.Sprintf(bitmex, path, path, path, path)
codebasePaths["exchanges bitstamp"] = fmt.Sprintf(bitstamp, path, path, path, path)
codebasePaths["exchanges bittrex"] = fmt.Sprintf(bittrex, path, path, path, path)
codebasePaths["exchanges btcc"] = fmt.Sprintf(btcc, path, path, path, path)
@@ -230,9 +235,11 @@ func addPaths() {
codebasePaths["exchanges coinut"] = fmt.Sprintf(coinut, path, path, path, path)
codebasePaths["exchanges exmo"] = fmt.Sprintf(exmo, path, path, path, path)
codebasePaths["exchanges coinbasepro"] = fmt.Sprintf(coinbasepro, path, path, path, path)
codebasePaths["exchanges gateio"] = fmt.Sprintf(gateio, path, path, path, path)
codebasePaths["exchanges gemini"] = fmt.Sprintf(gemini, path, path, path, path)
codebasePaths["exchanges hitbtc"] = fmt.Sprintf(hitbtc, path, path, path, path)
codebasePaths["exchanges huobi"] = fmt.Sprintf(huobi, path, path, path, path)
codebasePaths["exchanges huobihadax"] = fmt.Sprintf(huobihadax, path, path, path, path)
codebasePaths["exchanges itbit"] = fmt.Sprintf(itbit, path, path, path, path)
codebasePaths["exchanges kraken"] = fmt.Sprintf(kraken, path, path, path, path)
codebasePaths["exchanges lakebtc"] = fmt.Sprintf(lakebtc, path, path, path, path)
@@ -243,6 +250,7 @@ func addPaths() {
codebasePaths["exchanges poloniex"] = fmt.Sprintf(poloniex, path, path, path, path)
codebasePaths["exchanges wex"] = fmt.Sprintf(wex, path, path, path, path)
codebasePaths["exchanges yobit"] = fmt.Sprintf(yobit, path, path, path, path)
codebasePaths["exchanges zb"] = fmt.Sprintf(zb, path, path, path, path)
codebasePaths["CONTRIBUTORS"] = fmt.Sprintf(rootPath, path, path)
codebasePaths["LICENSE"] = fmt.Sprintf(rootPath, path, path)

View File

@@ -0,0 +1,98 @@
{{define "exchanges bitmex" -}}
{{template "header" .}}
## Bithumb Exchange
### Current Features
+ REST Support
### How to enable
+ [Enable via configuration](https://github.com/thrasher-/gocryptotrader/tree/master/config#enable-exchange-via-config-example)
+ Individual package example below:
```go
// Exchanges will be abstracted out in further updates and examples will be
// supplied then
```
### How to do REST public/private calls
+ If enabled via "configuration".json file the exchange will be added to the
IBotExchange array in the ```go var bot Bot``` and you will only be able to use
the wrapper interface functions for accessing exchange data. View routines.go
for an example of integration usage with GoCryptoTrader. Rudimentary example
below:
main.go
```go
var b exchange.IBotExchange
for i := range bot.exchanges {
if bot.exchanges[i].GetName() == "Bitmex" {
b = bot.exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
tick, err := b.GetTickerPrice()
if err != nil {
// Handle error
}
// Fetches current orderbook information
ob, err := b.GetOrderbookEx()
if err != nil {
// Handle error
}
// Private calls - wrapper functions - make sure your APIKEY and APISECRET are
// set and AuthenticatedAPISupport is set to true
// Fetches current account information
accountInfo, err := b.GetExchangeAccountInfo()
if err != nil {
// Handle error
}
```
+ If enabled via individually importing package, rudimentary example below:
```go
// Public calls
// Fetches current ticker information
ticker, err := b.GetTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
ob, err := b.GetOrderBook()
if err != nil {
// Handle error
}
// Private calls - make sure your APIKEY and APISECRET are set and
// AuthenticatedAPISupport is set to true
// GetUserInfo returns account info
accountInfo, err := b.GetUserInfo(...)
if err != nil {
// Handle error
}
// Submits an order and the exchange and returns its tradeID
tradeID, err := b.Trade(...)
if err != nil {
// Handle error
}
```
### Please click GoDocs chevron above to view current GoDoc information for this package
{{template "contributions"}}
{{template "donations"}}
{{end}}

View File

@@ -0,0 +1,105 @@
{{define "exchanges gateio" -}}
{{template "header" .}}
## GateIO Exchange
### Current Features
+ REST functions
### How to enable
+ [Enable via configuration](https://github.com/thrasher-/gocryptotrader/tree/master/config#enable-exchange-via-config-example)
+ Individual package example below:
```go
// Exchanges will be abstracted out in further updates and examples will be
// supplied then
```
### How to do REST public/private calls
+ If enabled via "configuration".json file the exchange will be added to the
IBotExchange array in the ```go var bot Bot``` and you will only be able to use
the wrapper interface functions for accessing exchange data. View routines.go
for an example of integration usage with GoCryptoTrader. Rudimentary example
below:
main.go
```go
var g exchange.IBotExchange
for i := range bot.exchanges {
if bot.exchanges[i].GetName() == "GateIO" {
g = bot.exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
tick, err := g.GetTickerPrice()
if err != nil {
// Handle error
}
// Fetches current orderbook information
ob, err := g.GetOrderbookEx()
if err != nil {
// Handle error
}
// Private calls - wrapper functions - make sure your APIKEY and APISECRET are
// set and AuthenticatedAPISupport is set to true
// Fetches current account information
accountInfo, err := g.GetExchangeAccountInfo()
if err != nil {
// Handle error
}
```
+ If enabled via individually importing package, rudimentary example below:
```go
// Public calls
// Fetches current ticker information
ticker, err := g.GetTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
ob, err := g.GetOrderBook()
if err != nil {
// Handle error
}
// Private calls - make sure your APIKEY and APISECRET are set and
// AuthenticatedAPISupport is set to true
// GetUserInfo returns account info
accountInfo, err := g.GetUserInfo(...)
if err != nil {
// Handle error
}
// Submits an order and the exchange and returns its tradeID
tradeID, err := g.Trade(...)
if err != nil {
// Handle error
}
```
### How to do LongPolling public/private calls
```go
// Exchanges will be abstracted out in further updates and examples will be
// supplied then
```
### Please click GoDocs chevron above to view current GoDoc information for this package
{{template "contributions"}}
{{template "donations"}}
{{end}}

View File

@@ -0,0 +1,105 @@
{{define "exchanges huobihadax" -}}
{{template "header" .}}
## HuobiHadax Exchange
### Current Features
+ REST functions
### How to enable
+ [Enable via configuration](https://github.com/thrasher-/gocryptotrader/tree/master/config#enable-exchange-via-config-example)
+ Individual package example below:
```go
// Exchanges will be abstracted out in further updates and examples will be
// supplied then
```
### How to do REST public/private calls
+ If enabled via "configuration".json file the exchange will be added to the
IBotExchange array in the ```go var bot Bot``` and you will only be able to use
the wrapper interface functions for accessing exchange data. View routines.go
for an example of integration usage with GoCryptoTrader. Rudimentary example
below:
main.go
```go
var h exchange.IBotExchange
for i := range bot.exchanges {
if bot.exchanges[i].GetName() == "HuobiHadax" {
h = bot.exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
tick, err := h.GetTickerPrice()
if err != nil {
// Handle error
}
// Fetches current orderbook information
ob, err := h.GetOrderbookEx()
if err != nil {
// Handle error
}
// Private calls - wrapper functions - make sure your APIKEY and APISECRET are
// set and AuthenticatedAPISupport is set to true
// Fetches current account information
accountInfo, err := h.GetExchangeAccountInfo()
if err != nil {
// Handle error
}
```
+ If enabled via individually importing package, rudimentary example below:
```go
// Public calls
// Fetches current ticker information
ticker, err := h.GetTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
ob, err := h.GetOrderBook()
if err != nil {
// Handle error
}
// Private calls - make sure your APIKEY and APISECRET are set and
// AuthenticatedAPISupport is set to true
// GetUserInfo returns account info
accountInfo, err := h.GetUserInfo(...)
if err != nil {
// Handle error
}
// Submits an order and the exchange and returns its tradeID
tradeID, err := h.Trade(...)
if err != nil {
// Handle error
}
```
### How to do LongPolling public/private calls
```go
// Exchanges will be abstracted out in further updates and examples will be
// supplied then
```
### Please click GoDocs chevron above to view current GoDoc information for this package
{{template "contributions"}}
{{template "donations"}}
{{end}}

View File

@@ -0,0 +1,105 @@
{{define "exchanges zb" -}}
{{template "header" .}}
## ZB Exchange
### Current Features
+ REST functions
### How to enable
+ [Enable via configuration](https://github.com/thrasher-/gocryptotrader/tree/master/config#enable-exchange-via-config-example)
+ Individual package example below:
```go
// Exchanges will be abstracted out in further updates and examples will be
// supplied then
```
### How to do REST public/private calls
+ If enabled via "configuration".json file the exchange will be added to the
IBotExchange array in the ```go var bot Bot``` and you will only be able to use
the wrapper interface functions for accessing exchange data. View routines.go
for an example of integration usage with GoCryptoTrader. Rudimentary example
below:
main.go
```go
var z exchange.IBotExchange
for i := range bot.exchanges {
if bot.exchanges[i].GetName() == "ZB" {
z = bot.exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
tick, err := z.GetTickerPrice()
if err != nil {
// Handle error
}
// Fetches current orderbook information
ob, err := z.GetOrderbookEx()
if err != nil {
// Handle error
}
// Private calls - wrapper functions - make sure your APIKEY and APISECRET are
// set and AuthenticatedAPISupport is set to true
// Fetches current account information
accountInfo, err := z.GetExchangeAccountInfo()
if err != nil {
// Handle error
}
```
+ If enabled via individually importing package, rudimentary example below:
```go
// Public calls
// Fetches current ticker information
ticker, err := z.GetTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
ob, err := z.GetOrderBook()
if err != nil {
// Handle error
}
// Private calls - make sure your APIKEY and APISECRET are set and
// AuthenticatedAPISupport is set to true
// GetUserInfo returns account info
accountInfo, err := z.GetUserInfo(...)
if err != nil {
// Handle error
}
// Submits an order and the exchange and returns its tradeID
tradeID, err := z.Trade(...)
if err != nil {
// Handle error
}
```
### How to do LongPolling public/private calls
```go
// Exchanges will be abstracted out in further updates and examples will be
// supplied then
```
### Please click GoDocs chevron above to view current GoDoc information for this package
{{template "contributions"}}
{{template "donations"}}
{{end}}

View File

@@ -25,6 +25,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
| Bitfinex | Yes | Yes | NA |
| Bitflyer | Yes | No | NA |
| Bithumb | Yes | NA | NA |
| BitMEX | Yes | No | NA |
| Bitstamp | Yes | Yes | No |
| Bittrex | Yes | No | NA |
| BTCC | Yes | Yes | No |