Added support for Bithumb exchange

This commit is contained in:
Ryan O'Hara-Reid
2018-01-31 14:44:52 +11:00
parent 039dd2e849
commit 3b8835d995
9 changed files with 1029 additions and 4 deletions

View File

@@ -21,6 +21,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
| Alphapoint | Yes | Yes | NA |
| ANXPRO | Yes | No | NA |
| Bitfinex | Yes | Yes | NA |
| Bithumb | Yes | NA | NA |
| Bitstamp | Yes | Yes | NA |
| Bittrex | Yes | No | NA |
| BTCC | Yes | Yes | No |
@@ -103,7 +104,7 @@ copy %GOPATH%\src\github.com\thrasher-\gocryptotrader\config_example.json %GOPAT
<img src="https://github.com/thrasher-/gocryptotrader/blob/master/web/src/assets/early-dumb-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:
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

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

View File

@@ -101,6 +101,28 @@
"Uppercase": true
}
},
{
"Name": "Bithumb",
"Enabled": true,
"Verbose": false,
"Websocket": false,
"UseSandbox": false,
"RESTPollingDelay": 10,
"AuthenticatedAPISupport": false,
"APIKey": "Key",
"APISecret": "Secret",
"ClientID": "ClientID",
"AvailablePairs": "BTCKRW,ETHKRW,DASHKRW,LTCKRW,ETCKRW,XRPKRW,BCHKRW,XMRKRW,ZECKRW,QTUMKRW,BTGKRW,EOSKRW",
"EnabledPairs": "BTCKRW,ETHKRW,DASHKRW,LTCKRW,ETCKRW,XRPKRW,BCHKRW,XMRKRW,ZECKRW,QTUMKRW,BTGKRW,EOSKRW",
"BaseCurrencies": "KRW",
"AssetTypes": "SPOT",
"ConfigCurrencyPairFormat": {
"Uppercase": true
},
"RequestCurrencyPairFormat": {
"Uppercase": true
}
},
{
"Name": "Bitstamp",
"Enabled": true,
@@ -501,4 +523,4 @@
}
}
]
}
}

View File

@@ -8,6 +8,7 @@ import (
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/anx"
"github.com/thrasher-/gocryptotrader/exchanges/bitfinex"
"github.com/thrasher-/gocryptotrader/exchanges/bithumb"
"github.com/thrasher-/gocryptotrader/exchanges/bitstamp"
"github.com/thrasher-/gocryptotrader/exchanges/bittrex"
"github.com/thrasher-/gocryptotrader/exchanges/btcc"
@@ -129,6 +130,8 @@ func LoadExchange(name string) error {
exch = new(anx.ANX)
case "bitfinex":
exch = new(bitfinex.Bitfinex)
case "bithumb":
exch = new(bithumb.Bithumb)
case "bitstamp":
exch = new(bitstamp.Bitstamp)
case "bittrex":

View File

@@ -0,0 +1,464 @@
package bithumb
import (
"bytes"
"errors"
"fmt"
"log"
"net/url"
"strconv"
"time"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
const (
apiURL = "https://api.bithumb.com"
noError = "0000"
// Public API
requestsPerSecondPublicAPI = 20
publicTicker = "/public/ticker/"
publicOrderBook = "/public/orderbook/"
publicRecentTransaction = "/public/recent_transactions/"
// Private API
requestsPerSecondPrivateAPI = 10
privateAccInfo = "/info/account"
privateAccBalance = "/info/balance"
privateWalletAdd = "/info/wallet_address"
privateTicker = "/info/ticker"
privateOrders = "/info/orders"
privateUserTrans = "/info/user_transactions"
privatePlaceTrade = "/trade/place"
privateOrderDetail = "/info/order_detail"
privateCancelTrade = "/trade/cancel"
privateBTCWithdraw = "/trade/btc_withdrawal"
privateKRWDeposit = "/trade/krw_deposit"
privateKRWWithdraw = "/trade/krw_withdrawal"
privateMarketBuy = "/trade/market_buy"
privateMarketSell = "/trade/market_sell"
)
// Bithumb is the overarching type across the Bithumb package
type Bithumb struct {
exchange.Base
}
// SetDefaults sets the basic defaults for Bithumb
func (b *Bithumb) SetDefaults() {
b.Name = "Bithumb"
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}
}
// Setup takes in the supplied exchange configuration details and sets params
func (b *Bithumb) 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)
}
}
}
// GetTicker returns ticker information
//
// symbol e.g. "btc"
func (b *Bithumb) GetTicker(symbol string) (Ticker, error) {
response := Ticker{}
path := fmt.Sprintf("%s%s%s", apiURL, publicTicker, common.StringToUpper(symbol))
return response, common.SendHTTPGetRequest(path, true, b.Verbose, &response)
}
// GetOrderBook returns current orderbook
//
// symbol e.g. "btc"
func (b *Bithumb) GetOrderBook(symbol string) (Orderbook, error) {
response := Orderbook{}
path := fmt.Sprintf("%s%s%s", apiURL, publicOrderBook, common.StringToUpper(symbol))
return response, common.SendHTTPGetRequest(path, true, b.Verbose, &response)
}
// GetRecentTransactions returns recent transactions
//
// symbol e.g. "btc"
func (b *Bithumb) GetRecentTransactions(symbol string) (RecentTransactions, error) {
response := RecentTransactions{}
path := fmt.Sprintf("%s%s%s", apiURL, publicRecentTransaction, common.StringToUpper(symbol))
return response, common.SendHTTPGetRequest(path, true, b.Verbose, &response)
}
// GetAccountInfo returns account information
func (b *Bithumb) GetAccountInfo() (Account, error) {
response := Account{}
err := b.SendAuthenticatedHTTPRequest(privateAccInfo, nil, &response)
if err != nil {
return response, err
}
if response.Status != noError {
return response, errors.New(response.Message)
}
return response, nil
}
// GetAccountBalance returns customer wallet information
func (b *Bithumb) GetAccountBalance() (Balance, error) {
response := Balance{}
err := b.SendAuthenticatedHTTPRequest(privateAccBalance, nil, &response)
if err != nil {
return response, err
}
if response.Status != noError {
return response, errors.New(response.Message)
}
return response, nil
}
// GetWalletAddress returns customer wallet address
//
// currency e.g. btc, ltc or "", will default to btc without currency specified
func (b *Bithumb) GetWalletAddress(currency string) (WalletAddressRes, error) {
response := WalletAddressRes{}
params := url.Values{}
params.Set("currency", common.StringToUpper(currency))
err := b.SendAuthenticatedHTTPRequest(privateWalletAdd, params, &response)
if err != nil {
return response, err
}
if response.Status != noError {
return response, errors.New(response.Message)
}
return response, nil
}
// GetLastTransaction returns customer last transaction
func (b *Bithumb) GetLastTransaction() (LastTransactionTicker, error) {
response := LastTransactionTicker{}
err := b.SendAuthenticatedHTTPRequest(privateTicker, nil, &response)
if err != nil {
return response, err
}
if response.Status != noError {
return response, errors.New(response.Message)
}
return response, nil
}
// GetOrders returns order list
//
// orderID: order number registered for purchase/sales
// transactionType: transaction type(bid : purchase, ask : sell)
// count: Value : 1 ~1000 (default : 100)
// after: YYYY-MM-DD hh:mm:ss's UNIX Timestamp
// (2014-11-28 16:40:01 = 1417160401000)
func (b *Bithumb) GetOrders(orderID, transactionType, count, after, currency string) (Orders, error) {
response := Orders{}
params := url.Values{}
params.Set("order_id", orderID)
params.Set("type", transactionType)
params.Set("count", count)
params.Set("after", after)
params.Set("currency", common.StringToUpper(currency))
err := b.SendAuthenticatedHTTPRequest(privateOrders, params, &response)
if err != nil {
return response, err
}
if response.Status != noError {
return response, errors.New(response.Message)
}
return response, nil
}
// GetUserTransactions returns customer transactions
func (b *Bithumb) GetUserTransactions() (UserTransactions, error) {
response := UserTransactions{}
err := b.SendAuthenticatedHTTPRequest(privateUserTrans, nil, &response)
if err != nil {
return response, err
}
if response.Status != noError {
return response, errors.New(response.Message)
}
return response, nil
}
// PlaceTrade executes a trade order
//
// orderCurrency: BTC, ETH, DASH, LTC, ETC, XRP, BCH, XMR, ZEC, QTUM, BTG, EOS
// (default value: BTC)
// transactionType: Transaction type(bid : purchase, ask : sales)
// units: Order quantity
// price: Transaction amount per currency
func (b *Bithumb) PlaceTrade(orderCurrency, transactionType string, units float64, price int64) (OrderPlace, error) {
response := OrderPlace{}
params := url.Values{}
params.Set("order_currency", common.StringToUpper(orderCurrency))
params.Set("Payment_currency", "KRW")
params.Set("type", common.StringToUpper(transactionType))
params.Set("units", strconv.FormatFloat(units, 'f', -1, 64))
params.Set("price", strconv.FormatInt(price, 10))
err := b.SendAuthenticatedHTTPRequest(privatePlaceTrade, params, &response)
if err != nil {
return response, err
}
if response.Status != noError {
return response, errors.New(response.Message)
}
return response, nil
}
// GetOrderDetails returns specific order details
//
// orderID: Order number registered for purchase/sales
// transactionType: Transaction type(bid : purchase, ask : sales)
// currency: BTC, ETH, DASH, LTC, ETC, XRP, BCH, XMR, ZEC, QTUM, BTG, EOS
// (default value: BTC)
func (b *Bithumb) GetOrderDetails(orderID, transactionType, currency string) (OrderDetails, error) {
response := OrderDetails{}
params := url.Values{}
params.Set("order_id", common.StringToUpper(orderID))
params.Set("type", common.StringToUpper(transactionType))
params.Set("currency", common.StringToUpper(currency))
err := b.SendAuthenticatedHTTPRequest(privateOrderDetail, params, &response)
if err != nil {
return response, err
}
if response.Status != noError {
return response, errors.New(response.Message)
}
return response, nil
}
// CancelTrade cancels a customer purchase/sales transaction
// transactionType: Transaction type(bid : purchase, ask : sales)
// orderID: Order number registered for purchase/sales
// currency: BTC, ETH, DASH, LTC, ETC, XRP, BCH, XMR, ZEC, QTUM, BTG, EOS
// (default value: BTC)
func (b *Bithumb) CancelTrade(transactionType, orderID, currency string) (ActionStatus, error) {
response := ActionStatus{}
params := url.Values{}
params.Set("order_id", common.StringToUpper(orderID))
params.Set("type", common.StringToUpper(transactionType))
params.Set("currency", common.StringToUpper(currency))
err := b.SendAuthenticatedHTTPRequest(privateCancelTrade, nil, &response)
if err != nil {
return response, err
}
if response.Status != noError {
return response, errors.New(response.Message)
}
return response, nil
}
// WithdrawCrypto withdraws a customer currency to an address
//
// address: Currency withdrawing address
// destination: Currency withdrawal Destination Tag (when withdraw XRP) OR
// Currency withdrawal Payment Id (when withdraw XMR)
// currency: BTC, ETH, DASH, LTC, ETC, XRP, BCH, XMR, ZEC, QTUM
// (default value: BTC)
// units: Quantity to withdraw currency
func (b *Bithumb) WithdrawCrypto(address, destination, currency string, units float64) (ActionStatus, error) {
response := ActionStatus{}
params := url.Values{}
params.Set("address", address)
params.Set("destination", destination)
params.Set("currency", common.StringToUpper(currency))
params.Set("units", strconv.FormatFloat(units, 'f', -1, 64))
err := b.SendAuthenticatedHTTPRequest(privateBTCWithdraw, params, &response)
if err != nil {
return response, err
}
if response.Status != noError {
return response, errors.New(response.Message)
}
return response, nil
}
// RequestKRWDepositDetails returns Bithumb banking details for deposit
// information
func (b *Bithumb) RequestKRWDepositDetails() (KRWDeposit, error) {
response := KRWDeposit{}
err := b.SendAuthenticatedHTTPRequest(privateKRWDeposit, nil, &response)
if err != nil {
return response, err
}
if response.Status != noError {
return response, errors.New(response.Message)
}
return response, nil
}
// RequestKRWWithdraw allows a customer KRW withdrawal request
//
// bank: Bankcode with bank name e.g. (bankcode)_(bankname)
// account: Withdrawing bank account number
// price: Withdrawing amount
func (b *Bithumb) RequestKRWWithdraw(bank, account string, price int64) (ActionStatus, error) {
response := ActionStatus{}
params := url.Values{}
params.Set("bank", bank)
params.Set("account", account)
params.Set("price", strconv.FormatInt(price, 10))
err := b.SendAuthenticatedHTTPRequest(privateKRWWithdraw, params, &response)
if err != nil {
return response, err
}
if response.Status != noError {
return response, errors.New(response.Message)
}
return response, nil
}
// MarketBuyOrder initiates a buy order through available order books
//
// currency: BTC, ETH, DASH, LTC, ETC, XRP, BCH, XMR, ZEC, QTUM, BTG, EOS
// (default value: BTC)
// units: Order quantity
func (b *Bithumb) MarketBuyOrder(currency string, units float64) (MarketBuy, error) {
response := MarketBuy{}
params := url.Values{}
params.Set("currency", common.StringToUpper(currency))
params.Set("units", strconv.FormatFloat(units, 'f', -1, 64))
err := b.SendAuthenticatedHTTPRequest(privateMarketBuy, params, &response)
if err != nil {
return response, err
}
if response.Status != noError {
return response, errors.New(response.Message)
}
return response, nil
}
// MarketSellOrder initiates a sell order through available order books
//
// currency: BTC, ETH, DASH, LTC, ETC, XRP, BCH, XMR, ZEC, QTUM, BTG, EOS
// (default value: BTC)
// units: Order quantity
func (b *Bithumb) MarketSellOrder(currency string, units float64) (MarketSell, error) {
response := MarketSell{}
params := url.Values{}
params.Set("currency", common.StringToUpper(currency))
params.Set("units", strconv.FormatFloat(units, 'f', -1, 64))
err := b.SendAuthenticatedHTTPRequest(privateMarketSell, params, &response)
if err != nil {
return response, err
}
if response.Status != noError {
return response, errors.New(response.Message)
}
return response, nil
}
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request to bithumb
func (b *Bithumb) SendAuthenticatedHTTPRequest(path string, params url.Values, result interface{}) error {
if !b.AuthenticatedAPISupport {
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, b.Name)
}
if params == nil {
params = url.Values{}
}
if b.Nonce.Get() == 0 {
b.Nonce.Set(time.Now().UnixNano() / int64(time.Millisecond))
} else {
b.Nonce.Inc()
}
params.Set("endpoint", path)
payload := params.Encode()
hmacPayload := path + string(0) + payload + string(0) + b.Nonce.String()
hmac := common.GetHMAC(common.HashSHA512, []byte(hmacPayload), []byte(b.APISecret))
hmacStr := common.HexEncodeToString(hmac)
headers := make(map[string]string)
headers["Api-Key"] = b.APIKey
headers["Api-Sign"] = common.Base64Encode([]byte(hmacStr))
headers["Api-Nonce"] = b.Nonce.String()
headers["Content-Type"] = "application/x-www-form-urlencoded"
resp, err := common.SendHTTPRequest(
"POST", apiURL+path, headers, bytes.NewBufferString(payload),
)
if err != nil {
return err
}
if b.Verbose {
log.Printf("Received raw: \n%s\n", resp)
}
if err = common.JSONDecode([]byte(resp), &result); err != nil {
return errors.New("sendAuthenticatedHTTPRequest: Unable to JSON Unmarshal response." + err.Error())
}
return nil
}

View File

@@ -0,0 +1,202 @@
package bithumb
import (
"testing"
"github.com/thrasher-/gocryptotrader/config"
)
// Please supply your own keys here for due diligence testing
const (
testAPIKey = ""
testAPISecret = ""
)
var b Bithumb
func TestSetDefaults(t *testing.T) {
b.SetDefaults()
}
func TestSetup(t *testing.T) {
cfg := config.GetConfig()
cfg.LoadConfig("../../testdata/configtest.json")
bitConfig, err := cfg.GetExchangeConfig("Bithumb")
if err != nil {
t.Error("Test Failed - Bithumb Setup() init error")
}
bitConfig.AuthenticatedAPISupport = true
bitConfig.APIKey = testAPIKey
bitConfig.APISecret = testAPISecret
b.Setup(bitConfig)
}
func TestGetTicker(t *testing.T) {
t.Parallel()
_, err := b.GetTicker("btc")
if err != nil {
t.Error("test failed - Bithumb GetTicker() error", err)
}
}
func TestGetOrderBook(t *testing.T) {
t.Parallel()
_, err := b.GetOrderBook("btc")
if err != nil {
t.Error("test failed - Bithumb GetOrderBook() error", err)
}
}
func TestGetRecentTransactions(t *testing.T) {
t.Parallel()
_, err := b.GetRecentTransactions("btc")
if err != nil {
t.Error("test failed - Bithumb GetRecentTransactions() error", err)
}
}
func TestGetAccountInfo(t *testing.T) {
t.Parallel()
_, err := b.GetAccountInfo()
if err == nil {
t.Error("test failed - Bithumb GetAccountInfo() error", err)
}
}
func TestGetAccountBalance(t *testing.T) {
t.Parallel()
_, err := b.GetAccountBalance()
if err == nil {
t.Error("test failed - Bithumb GetAccountBalance() error", err)
}
}
func TestGetWalletAddress(t *testing.T) {
t.Parallel()
_, err := b.GetWalletAddress("")
if err == nil {
t.Error("test failed - Bithumb GetWalletAddress() error", err)
}
}
func TestGetLastTransaction(t *testing.T) {
t.Parallel()
_, err := b.GetLastTransaction()
if err == nil {
t.Error("test failed - Bithumb GetLastTransaction() error", err)
}
}
func TestGetOrders(t *testing.T) {
t.Parallel()
_, err := b.GetOrders("1337", "bid", "100", "", "BTC")
if err == nil {
t.Error("test failed - Bithumb GetOrders() error", err)
}
}
func TestGetUserTransactions(t *testing.T) {
t.Parallel()
_, err := b.GetUserTransactions()
if err == nil {
t.Error("test failed - Bithumb GetUserTransactions() error", err)
}
}
func TestPlaceTrade(t *testing.T) {
t.Parallel()
_, err := b.PlaceTrade("btc", "bid", 0, 0)
if err == nil {
t.Error("test failed - Bithumb PlaceTrade() error", err)
}
}
func TestGetOrderDetails(t *testing.T) {
t.Parallel()
_, err := b.GetOrderDetails("1337", "bid", "btc")
if err == nil {
t.Error("test failed - Bithumb GetOrderDetails() error", err)
}
}
func TestCancelTrade(t *testing.T) {
t.Parallel()
_, err := b.CancelTrade("", "", "")
if err == nil {
t.Error("test failed - Bithumb CancelTrade() error", err)
}
}
func TestWithdrawCrypto(t *testing.T) {
t.Parallel()
_, err := b.WithdrawCrypto("LQxiDhKU7idKiWQhx4ALKYkBx8xKEQVxJR", "", "ltc", 0)
if err == nil {
t.Error("test failed - Bithumb WithdrawCrypto() error", err)
}
}
func TestRequestKRWDepositDetails(t *testing.T) {
t.Parallel()
_, err := b.RequestKRWDepositDetails()
if err == nil {
t.Error("test failed - Bithumb RequestKRWDepositDetails() error", err)
}
}
func TestRequestKRWWithdraw(t *testing.T) {
t.Parallel()
_, err := b.RequestKRWWithdraw("102_bank", "1337", 1000)
if err == nil {
t.Error("test failed - Bithumb RequestKRWWithdraw() error", err)
}
}
func TestMarketBuyOrder(t *testing.T) {
t.Parallel()
_, err := b.MarketBuyOrder("btc", 0)
if err == nil {
t.Error("test failed - Bithumb MarketBuyOrder() error", err)
}
}
func TestMarketSellOrder(t *testing.T) {
t.Parallel()
_, err := b.MarketSellOrder("btc", 0)
if err == nil {
t.Error("test failed - Bithumb MarketSellOrder() error", err)
}
}
func TestRun(t *testing.T) {
t.Parallel()
b.Run()
}
func TestUpdateTicker(t *testing.T) {
t.Parallel()
pair := b.GetEnabledCurrencies()[0]
_, err := b.UpdateTicker(pair, b.AssetTypes[0])
if err != nil {
t.Error("test failed - Bithumb UpdateTicker() error", err)
}
}
func TestGetTickerPrice(t *testing.T) {
t.Parallel()
pair := b.GetEnabledCurrencies()[0]
_, err := b.GetTickerPrice(pair, b.AssetTypes[0])
if err != nil {
t.Error("test failed - Bithumb GetTickerPrice() error", err)
}
}
func TestGetOrderbookEx(t *testing.T) {
t.Parallel()
pair := b.GetEnabledCurrencies()[0]
_, err := b.GetOrderbookEx(pair, b.AssetTypes[0])
if err != nil {
t.Error("test failed - Bithumb GetOrderbookEx() error", err)
}
}

View File

@@ -0,0 +1,217 @@
package bithumb
// Ticker holds the standard ticker information
type Ticker struct {
Status string `json:"status"`
Data struct {
OpeningPrice float64 `json:"opening_price,string"`
ClosingPrice float64 `json:"closing_price,string"`
MinPrice float64 `json:"min_price,string"`
MaxPrice float64 `json:"max_price,string"`
AveragePrice float64 `json:"average_price,string"`
UnitsTraded float64 `json:"units_traded,string"`
Volume1Day float64 `json:"volume_1day,string"`
Volume7Day float64 `json:"volume_7day,string"`
BuyPrice float64 `json:"buy_price,string"`
SellPrice float64 `json:"sell_price,string"`
Date int64 `json:"date,string"`
} `json:"data"`
Message string `json:"message"`
}
// Orderbook holds full range of order book information
type Orderbook struct {
Status string `json:"status"`
Data struct {
Timestamp int64 `json:"timestamp,string"`
OrderCurrency string `json:"order_currency"`
PaymentCurrency string `json:"payment_currency"`
Bids []struct {
Quantity float64 `json:"quantity,string"`
Price float64 `json:"price,string"`
} `json:"bids"`
Asks []struct {
Quantity float64 `json:"quantity,string"`
Price float64 `json:"price,string"`
} `json:"asks"`
} `json:"data"`
Message string `json:"message"`
}
// RecentTransactions holds history of completed transaction data
type RecentTransactions struct {
Status string `json:"status"`
Data []struct {
TransactionDate string `json:"transaction_date"`
Type string `json:"type"`
UnitsTraded float64 `json:"units_traded,string"`
Price float64 `json:"price,string"`
Total float64 `json:"total,string"`
} `json:"data"`
Message string `json:"message"`
}
// Account holds account details
type Account struct {
Status string `json:"status"`
Data struct {
Created int64 `json:"created,string"`
AccountID string `json:"account_id"`
TradeFee float64 `json:"trade_fee,string"`
Balance float64 `json:"balance,string"`
} `json:"data"`
Message string `json:"message"`
}
// Balance holds balance details
type Balance struct {
Status string `json:"status"`
Data struct {
TotalBTC float64 `json:"total_btc,string"`
TotalKRW float64 `json:"total_krw"`
InUseBTC float64 `json:"in_use_btc,string"`
InUseKRW float64 `json:"in_use_krw"`
AvailableBTC float64 `json:"available_btc,string"`
AvailableKRW float64 `json:"available_krw"`
MisuKRW float64 `json:"misu_krw"`
MisuBTC float64 `json:"misu_btc,string"`
XcoinLast float64 `json:"xcoin_last,string"`
} `json:"data"`
Message string `json:"message"`
}
// WalletAddressRes contains wallet address information
type WalletAddressRes struct {
Status string `json:"status"`
Data struct {
WalletAddress string `json:"wallet_address"`
Currency string `json:"currency"`
} `json:"data"`
Message string `json:"message"`
}
// LastTransactionTicker holds customer last transaction information
type LastTransactionTicker struct {
Status string `json:"status"`
Data struct {
OpeningPrice float64 `json:"opening_price,string"`
ClosingPrice float64 `json:"closing_price,string"`
MinPrice float64 `json:"min_price,string"`
MaxPrice float64 `json:"max_price,string"`
AveragePrice float64 `json:"average_price,string"`
UnitsTraded float64 `json:"units_traded,string"`
Volume1Day float64 `json:"volume_1day,string"`
Volume7Day float64 `json:"volume_7day,string"`
BuyPrice int64 `json:"buy_price,string"`
SellPrice int64 `json:"sell_price,string"`
Date int64 `json:"date,string"`
} `json:"data"`
Message string `json:"message"`
}
// Orders contains information about your current orders
type Orders struct {
Status string `json:"status"`
Data []struct {
OrderID string `json:"order_id"`
OrderCurrency string `json:"order_currency"`
OrderDate int64 `json:"order_date"`
PaymentCurrency string `json:"payment_currency"`
Type string `json:"type"`
Status string `json:"status"`
Units float64 `json:"units,string"`
UnitsRemaining float64 `json:"units_remaining,string"`
Price float64 `json:"price,string"`
Fee float64 `json:"fee,string"`
Total float64 `json:"total,string"`
DateCompleted int64 `json:"date_completed"`
} `json:"data"`
Message string `json:"message"`
}
// UserTransactions holds users full transaction list
type UserTransactions struct {
Status string `json:"status"`
Data []struct {
Search string `json:"search"`
TransferDate int64 `json:"transfer_date"`
Units string `json:"units"`
Price float64 `json:"price,string"`
BTC1KRW float64 `json:"btc1krw,string"`
Fee string `json:"fee"`
BTCRemain float64 `json:"btc_remain,string"`
KRWRemain float64 `json:"krw_remain,string"`
} `json:"data"`
Message string `json:"message"`
}
// OrderPlace contains order information
type OrderPlace struct {
Status string `json:"status"`
Data []struct {
ContID string `json:"cont_id"`
Units float64 `json:"units,string"`
Price float64 `json:"price,string"`
Total float64 `json:"total,string"`
Fee float64 `json:"fee,string"`
} `json:"data"`
Message string `json:"message"`
}
// OrderDetails contains specific order information
type OrderDetails struct {
Status string `json:"status"`
Data []struct {
TransactionDate int64 `json:"transaction_date,string"`
Type string `json:"type"`
OrderCurrency string `json:"order_currency"`
PaymentCurrency string `json:"payment_currency"`
UnitsTraded float64 `json:"units_traded,string"`
Price float64 `json:"price,string"`
Total float64 `json:"total,string"`
} `json:"data"`
Message string `json:"message"`
}
// ActionStatus holds the return status
type ActionStatus struct {
Status string `json:"status"`
Message string `json:"message"`
}
// KRWDeposit resp type for a KRW deposit
type KRWDeposit struct {
Status string `json:"status"`
Account string `json:"account"`
Bank string `json:"bank"`
BankUser string `json:"BankUser"`
Message string `json:"message"`
}
// MarketBuy holds market buy order information
type MarketBuy struct {
Status string `json:"status"`
OrderID string `json:"order_id"`
Data []struct {
ContID string `json:"cont_id"`
Units float64 `json:"units,string"`
Price float64 `json:"price,string"`
Total float64 `json:"total,string"`
Fee float64 `json:"fee,string"`
} `json:"data"`
Message string `json:"message"`
}
// MarketSell holds market buy order information
type MarketSell struct {
Status string `json:"status"`
OrderID string `json:"order_id"`
Data []struct {
ContID string `json:"cont_id"`
Units float64 `json:"units,string"`
Price float64 `json:"price,string"`
Total float64 `json:"total,string"`
Fee float64 `json:"fee,string"`
} `json:"data"`
Message string `json:"message"`
}

View File

@@ -0,0 +1,94 @@
package bithumb
import (
"errors"
"log"
"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 OKEX go routine
func (b *Bithumb) Start() {
go b.Run()
}
// Run implements the OKEX wrapper
func (b *Bithumb) 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)
}
}
// UpdateTicker updates and returns the ticker for a currency pair
func (b *Bithumb) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
var tickerPrice ticker.Price
item := p.GetFirstCurrency().String()
tick, err := b.GetTicker(item)
if err != nil {
return tickerPrice, err
}
tickerPrice.Pair = p
tickerPrice.Ask = tick.Data.SellPrice
tickerPrice.Bid = tick.Data.BuyPrice
tickerPrice.Low = tick.Data.MinPrice
tickerPrice.Last = tick.Data.ClosingPrice
tickerPrice.Volume = tick.Data.Volume1Day
tickerPrice.High = tick.Data.MaxPrice
ticker.ProcessTicker(b.GetName(), p, tickerPrice, assetType)
return ticker.GetTicker(b.Name, p, assetType)
}
// GetTickerPrice returns the ticker for a currency pair
func (b *Bithumb) 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 *Bithumb) 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 *Bithumb) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
var orderBook orderbook.Base
currency := p.GetFirstCurrency().String()
orderbookNew, err := b.GetOrderBook(currency)
if err != nil {
return orderBook, err
}
for _, bids := range orderbookNew.Data.Bids {
orderBook.Bids = append(orderBook.Bids, orderbook.Item{Amount: bids.Quantity, Price: bids.Price})
}
for _, asks := range orderbookNew.Data.Asks {
orderBook.Asks = append(orderBook.Asks, orderbook.Item{Amount: asks.Quantity, Price: asks.Price})
}
orderbook.ProcessOrderbook(b.GetName(), p, orderBook, assetType)
return orderbook.GetOrderbook(b.Name, p, assetType)
}
// GetExchangeAccountInfo retrieves balances for all enabled currencies for the
// Bithumb exchange
func (b *Bithumb) GetExchangeAccountInfo() (exchange.AccountInfo, error) {
var response exchange.AccountInfo
return response, errors.New("not implemented")
}

View File

@@ -101,6 +101,28 @@
"Uppercase": true
}
},
{
"Name": "Bithumb",
"Enabled": true,
"Verbose": false,
"Websocket": false,
"UseSandbox": false,
"RESTPollingDelay": 10,
"AuthenticatedAPISupport": false,
"APIKey": "Key",
"APISecret": "Secret",
"ClientID": "ClientID",
"AvailablePairs": "BTCKRW,ETHKRW,DASHKRW,LTCKRW,ETCKRW,XRPKRW,BCHKRW,XMRKRW,ZECKRW,QTUMKRW,BTGKRW,EOSKRW",
"EnabledPairs": "BTCKRW,ETHKRW,DASHKRW,LTCKRW,ETCKRW,XRPKRW,BCHKRW,XMRKRW,ZECKRW,QTUMKRW,BTGKRW,EOSKRW",
"BaseCurrencies": "KRW",
"AssetTypes": "SPOT",
"ConfigCurrencyPairFormat": {
"Uppercase": true
},
"RequestCurrencyPairFormat": {
"Uppercase": true
}
},
{
"Name": "Bitstamp",
"Enabled": true,