diff --git a/exchanges/alphapoint/alphapoint.go b/exchanges/alphapoint/alphapoint.go index 987d951d..8fc7f54d 100644 --- a/exchanges/alphapoint/alphapoint.go +++ b/exchanges/alphapoint/alphapoint.go @@ -359,17 +359,26 @@ func (a *Alphapoint) WithdrawCoins(symbol, product, address string, amount float return nil } +func (a *Alphapoint) convertOrderTypeToOrderTypeNumber(orderType string) (orderTypeNumber int64) { + if orderType == exchange.Market.ToString() { + orderTypeNumber = 1 + } + + return orderTypeNumber +} + // CreateOrder creates a market or limit order // symbol - Instrument code (ex: “BTCUSD”) // side - “buy” or “sell” // orderType - “1” for market orders, “0” for limit orders // quantity - Quantity // price - Price in USD -func (a *Alphapoint) CreateOrder(symbol, side string, orderType int, quantity, price float64) (int64, error) { +func (a *Alphapoint) CreateOrder(symbol, side, orderType string, quantity, price float64) (int64, error) { + orderTypeNumber := a.convertOrderTypeToOrderTypeNumber(orderType) request := make(map[string]interface{}) request["ins"] = symbol request["side"] = side - request["orderType"] = orderType + request["orderType"] = orderTypeNumber request["qty"] = strconv.FormatFloat(quantity, 'f', -1, 64) request["px"] = strconv.FormatFloat(price, 'f', -1, 64) response := Response{} diff --git a/exchanges/alphapoint/alphapoint_test.go b/exchanges/alphapoint/alphapoint_test.go index b19b42d7..f6c0bbe0 100644 --- a/exchanges/alphapoint/alphapoint_test.go +++ b/exchanges/alphapoint/alphapoint_test.go @@ -411,7 +411,7 @@ func TestCreateOrder(t *testing.T) { return } - _, err := a.CreateOrder("", "", 1, 0.01, 0) + _, err := a.CreateOrder("", "", exchange.Market.ToString(), 0.01, 0) if err == nil { t.Error("Test Failed - GetUserInfo() error") } diff --git a/exchanges/alphapoint/alphapoint_wrapper.go b/exchanges/alphapoint/alphapoint_wrapper.go index 543b145e..496a29b7 100644 --- a/exchanges/alphapoint/alphapoint_wrapper.go +++ b/exchanges/alphapoint/alphapoint_wrapper.go @@ -2,6 +2,7 @@ package alphapoint import ( "errors" + "fmt" "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/exchanges" @@ -105,9 +106,19 @@ func (a *Alphapoint) GetExchangeHistory(p pair.CurrencyPair, assetType string) ( // SubmitExchangeOrder submits a new order and returns a true value when // successfully submitted -func (a *Alphapoint) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - //return a.CreateOrder(p.Pair().String(), side, orderType, amount, price) - return 0, errors.New("not yet implemented") +func (a *Alphapoint) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + + response, err := a.CreateOrder(p.Pair().String(), side.ToString(), orderType.ToString(), amount, price) + if response > 0 { + submitOrderResponse.OrderID = fmt.Sprintf("%v", response) + } + + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/anx/anx.go b/exchanges/anx/anx.go index ac3c4800..e28a0ed7 100644 --- a/exchanges/anx/anx.go +++ b/exchanges/anx/anx.go @@ -78,7 +78,7 @@ func (a *ANX) Setup(exch config.ExchangeConfig) { } else { a.Enabled = true a.AuthenticatedAPISupport = exch.AuthenticatedAPISupport - a.SetAPIKeys(exch.APIKey, exch.APISecret, "", true) + a.SetAPIKeys(exch.APIKey, exch.APISecret, "", false) a.SetHTTPClientTimeout(exch.HTTPTimeout) a.SetHTTPClientUserAgent(exch.HTTPUserAgent) a.RESTPollingDelay = exch.RESTPollingDelay @@ -196,10 +196,10 @@ func (a *ANX) GetDataToken() (string, error) { } // NewOrder sends a new order request to the exchange. -func (a *ANX) NewOrder(orderType string, buy bool, tradedCurrency, tradedCurrencyAmount, settlementCurrency, settlementCurrencyAmount, limitPriceSettlement string, - replace bool, replaceUUID string, replaceIfActive bool) error { - request := make(map[string]interface{}) +func (a *ANX) NewOrder(orderType string, buy bool, tradedCurrency string, tradedCurrencyAmount float64, settlementCurrency string, settlementCurrencyAmount float64, limitPriceSettlement float64, + replace bool, replaceUUID string, replaceIfActive bool) (string, error) { + request := make(map[string]interface{}) var order Order order.OrderType = orderType order.BuyTradedCurrency = buy @@ -223,20 +223,20 @@ func (a *ANX) NewOrder(orderType string, buy bool, tradedCurrency, tradedCurrenc type OrderResponse struct { OrderID string `json:"orderId"` - Timestamp int64 `json:"timestamp"` + Timestamp int64 `json:"timestamp,string"` ResultCode string `json:"resultCode"` } var response OrderResponse err := a.SendAuthenticatedHTTPRequest(anxOrderNew, request, &response) if err != nil { - return err + return "", err } if response.ResultCode != "OK" { - return errors.New("Response code is not OK: %s" + response.ResultCode) + return "", errors.New("Response code is not OK: " + response.ResultCode) } - return nil + return response.OrderID, nil } // OrderInfo returns information about a specific order diff --git a/exchanges/anx/anx_test.go b/exchanges/anx/anx_test.go index 064c3e06..44b75bd2 100644 --- a/exchanges/anx/anx_test.go +++ b/exchanges/anx/anx_test.go @@ -4,12 +4,17 @@ import ( "testing" "github.com/thrasher-/gocryptotrader/config" + "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" exchange "github.com/thrasher-/gocryptotrader/exchanges" ) var a ANX +const ( + canPlaceOrders = false +) + func TestSetDefaults(t *testing.T) { a.SetDefaults() @@ -40,6 +45,8 @@ func TestSetup(t *testing.T) { anxSetupConfig := config.GetConfig() anxSetupConfig.LoadConfig("../../testdata/configtest.json") anxConfig, err := anxSetupConfig.GetExchangeConfig("ANX") + anxConfig.AuthenticatedAPISupport = true + if err != nil { t.Error("Test Failed - ANX Setup() init error") } @@ -48,15 +55,7 @@ func TestSetup(t *testing.T) { if a.Enabled != true { t.Error("Test Failed - ANX Setup() incorrect values set") } - if a.AuthenticatedAPISupport != false { - t.Error("Test Failed - ANX Setup() incorrect values set") - } - if len(a.APIKey) != 0 { - t.Error("Test Failed - ANX Setup() incorrect values set") - } - if len(a.APISecret) != 0 { - t.Error("Test Failed - ANX Setup() incorrect values set") - } + if a.RESTPollingDelay != 10 { t.Error("Test Failed - ANX Setup() incorrect values set") } @@ -220,3 +219,25 @@ func TestFormatWithdrawPermissions(t *testing.T) { t.Errorf("Expected: %s, Recieved: %s", expectedResult, withdrawPermissions) } } + +// This will really really use the API to place an order +// If you're going to test this, make sure you're willing to place real orders on the exchange +func TestSubmitOrder(t *testing.T) { + a.SetDefaults() + TestSetup(t) + + if a.APIKey == "" || a.APISecret == "" || + a.APIKey == "Key" || a.APISecret == "Secret" || + !canPlaceOrders { + t.Skip() + } + var p = pair.CurrencyPair{ + Delimiter: "_", + FirstCurrency: symbol.BTC, + SecondCurrency: symbol.USD, + } + response, err := a.SubmitExchangeOrder(p, exchange.Buy, exchange.Market, 1, 1, "clientId") + if err != nil || !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } +} diff --git a/exchanges/anx/anx_types.go b/exchanges/anx/anx_types.go index 7794bf35..a874f290 100644 --- a/exchanges/anx/anx_types.go +++ b/exchanges/anx/anx_types.go @@ -99,15 +99,15 @@ type CurrenciesStaticResponse struct { // Order holds order information type Order struct { - OrderType string `json:"orderType"` - BuyTradedCurrency bool `json:"buyTradedCurrency"` - TradedCurrency string `json:"tradedCurrency"` - SettlementCurrency string `json:"settlementCurrency"` - TradedCurrencyAmount string `json:"tradedCurrencyAmount"` - SettlementCurrencyAmount string `json:"settlementCurrencyAmount"` - LimitPriceInSettlementCurrency string `json:"limitPriceInSettlementCurrency"` - ReplaceExistingOrderUUID string `json:"replaceExistingOrderUuid"` - ReplaceOnlyIfActive bool `json:"replaceOnlyIfActive"` + OrderType string `json:"orderType"` + BuyTradedCurrency bool `json:"buyTradedCurrency"` + TradedCurrency string `json:"tradedCurrency"` + SettlementCurrency string `json:"settlementCurrency"` + TradedCurrencyAmount float64 `json:"tradedCurrencyAmount,string"` + SettlementCurrencyAmount float64 `json:"settlementCurrencyAmount,string"` + LimitPriceInSettlementCurrency float64 `json:"limitPriceInSettlementCurrency,string"` + ReplaceExistingOrderUUID string `json:"replaceExistingOrderUuid"` + ReplaceOnlyIfActive bool `json:"replaceOnlyIfActive"` } // OrderResponse holds order response data diff --git a/exchanges/anx/anx_wrapper.go b/exchanges/anx/anx_wrapper.go index 5768c69d..145b2759 100644 --- a/exchanges/anx/anx_wrapper.go +++ b/exchanges/anx/anx_wrapper.go @@ -196,8 +196,30 @@ func (a *ANX) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]excha } // SubmitExchangeOrder submits a new order -func (a *ANX) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func (a *ANX) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + + var isBuying bool + var limitPriceInSettlementCurrency float64 + + if side == exchange.Buy { + isBuying = true + } + + if orderType == exchange.Limit { + limitPriceInSettlementCurrency = price + } + + response, err := a.NewOrder(orderType.ToString(), isBuying, p.FirstCurrency.String(), amount, p.SecondCurrency.String(), amount, limitPriceInSettlementCurrency, false, "", false) + if response != "" { + submitOrderResponse.OrderID = response + } + + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/binance/binance.go b/exchanges/binance/binance.go index 389535b3..da9f9dc8 100644 --- a/exchanges/binance/binance.go +++ b/exchanges/binance/binance.go @@ -445,8 +445,12 @@ func (b *Binance) NewOrder(o NewOrderRequest) (NewOrderResponse, error) { params.Set("side", string(o.Side)) params.Set("type", string(o.TradeType)) params.Set("quantity", strconv.FormatFloat(o.Quantity, 'f', -1, 64)) - params.Set("price", strconv.FormatFloat(o.Price, 'f', -1, 64)) - params.Set("timeInForce", string(o.TimeInForce)) + if o.TradeType == "LIMIT" { + params.Set("price", strconv.FormatFloat(o.Price, 'f', -1, 64)) + } + if o.TimeInForce != "" { + params.Set("timeInForce", string(o.TimeInForce)) + } if o.NewClientOrderID != "" { params.Set("newClientOrderID", o.NewClientOrderID) diff --git a/exchanges/binance/binance_test.go b/exchanges/binance/binance_test.go index 6d687a0d..57d01ff9 100644 --- a/exchanges/binance/binance_test.go +++ b/exchanges/binance/binance_test.go @@ -3,6 +3,7 @@ package binance import ( "testing" + "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" "github.com/thrasher-/gocryptotrader/config" @@ -11,8 +12,9 @@ import ( // Please supply your own keys here for due diligence testing const ( - testAPIKey = "" - testAPISecret = "" + testAPIKey = "" + testAPISecret = "" + canPlaceOrders = false ) var b Binance @@ -336,3 +338,25 @@ func TestFormatWithdrawPermissions(t *testing.T) { t.Errorf("Expected: %s, Recieved: %s", expectedResult, withdrawPermissions) } } + +// This will really really use the API to place an order +// If you're going to test this, make sure you're willing to place real orders on the exchange +func TestSubmitOrder(t *testing.T) { + b.SetDefaults() + TestSetup(t) + + if b.APIKey == "" || b.APISecret == "" || + b.APIKey == "Key" || b.APISecret == "Secret" || + !canPlaceOrders { + t.Skip() + } + var p = pair.CurrencyPair{ + Delimiter: "", + FirstCurrency: symbol.LTC, + SecondCurrency: symbol.BTC, + } + response, err := b.SubmitExchangeOrder(p, exchange.Buy, exchange.Market, 1, 1, "clientId") + if err != nil || !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } +} diff --git a/exchanges/binance/binance_wrapper.go b/exchanges/binance/binance_wrapper.go index a7a9c13b..ef3a6f75 100644 --- a/exchanges/binance/binance_wrapper.go +++ b/exchanges/binance/binance_wrapper.go @@ -2,6 +2,7 @@ package binance import ( "errors" + "fmt" "log" "sync" @@ -141,8 +142,45 @@ func (b *Binance) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]e } // SubmitExchangeOrder submits a new order -func (b *Binance) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func (b *Binance) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + + var sideType RequestParamsSideType + if side == exchange.Buy { + sideType = BinanceRequestParamsSideBuy + } else { + sideType = BinanceRequestParamsSideSell + } + + var requestParamsOrderType RequestParamsOrderType + if orderType == exchange.Market { + requestParamsOrderType = BinanceRequestParamsOrderMarket + } else if orderType == exchange.Limit { + requestParamsOrderType = BinanceRequestParamsOrderLimit + } else { + submitOrderResponse.IsOrderPlaced = false + return submitOrderResponse, errors.New("Unsupported order type") + } + + var orderRequest = NewOrderRequest{ + Symbol: p.FirstCurrency.String() + p.SecondCurrency.String(), + Side: sideType, + Price: price, + Quantity: amount, + TradeType: requestParamsOrderType, + } + + response, err := b.NewOrder(orderRequest) + + if response.OrderID > 0 { + submitOrderResponse.OrderID = fmt.Sprintf("%v", response.OrderID) + } + + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/bitfinex/bitfinex_test.go b/exchanges/bitfinex/bitfinex_test.go index 2459c340..cb160a87 100644 --- a/exchanges/bitfinex/bitfinex_test.go +++ b/exchanges/bitfinex/bitfinex_test.go @@ -8,14 +8,16 @@ import ( "github.com/thrasher-/gocryptotrader/common" "github.com/thrasher-/gocryptotrader/config" + "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" exchange "github.com/thrasher-/gocryptotrader/exchanges" ) // Please supply your own keys here to do better tests const ( - testAPIKey = "" - testAPISecret = "" + testAPIKey = "" + testAPISecret = "" + canPlaceOrders = false ) var b Bitfinex @@ -718,3 +720,25 @@ func TestFormatWithdrawPermissions(t *testing.T) { t.Errorf("Expected: %s, Recieved: %s", expectedResult, withdrawPermissions) } } + +// This will really really use the API to place an order +// If you're going to test this, make sure you're willing to place real orders on the exchange +func TestSubmitOrder(t *testing.T) { + b.SetDefaults() + TestSetup(t) + + if b.APIKey == "" || b.APISecret == "" || + b.APIKey == "Key" || b.APISecret == "Secret" || + !canPlaceOrders { + t.Skip() + } + var p = pair.CurrencyPair{ + Delimiter: "", + FirstCurrency: symbol.LTC, + SecondCurrency: symbol.BTC, + } + response, err := b.SubmitExchangeOrder(p, exchange.Buy, exchange.Market, 1, 1, "clientId") + if err != nil || !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } +} diff --git a/exchanges/bitfinex/bitfinex_wrapper.go b/exchanges/bitfinex/bitfinex_wrapper.go index a7c0265c..09b967fa 100644 --- a/exchanges/bitfinex/bitfinex_wrapper.go +++ b/exchanges/bitfinex/bitfinex_wrapper.go @@ -2,6 +2,7 @@ package bitfinex import ( "errors" + "fmt" "log" "net/url" "sync" @@ -174,8 +175,25 @@ func (b *Bitfinex) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([] } // SubmitExchangeOrder submits a new order -func (b *Bitfinex) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func (b *Bitfinex) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + var isBuying bool + + if side == exchange.Buy { + isBuying = true + } + + response, err := b.NewOrder(p.Pair().String(), amount, price, isBuying, orderType.ToString(), false) + + if response.OrderID > 0 { + submitOrderResponse.OrderID = fmt.Sprintf("%v", response.OrderID) + } + + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/bitflyer/bitflyer_test.go b/exchanges/bitflyer/bitflyer_test.go index 6cf3835b..575ace59 100644 --- a/exchanges/bitflyer/bitflyer_test.go +++ b/exchanges/bitflyer/bitflyer_test.go @@ -13,8 +13,9 @@ import ( // Please supply your own keys here for due diligence testing const ( - testAPIKey = "" - testAPISecret = "" + testAPIKey = "" + testAPISecret = "" + canPlaceOrders = false ) var b Bitflyer @@ -246,3 +247,25 @@ func TestFormatWithdrawPermissions(t *testing.T) { t.Errorf("Expected: %s, Recieved: %s", expectedResult, withdrawPermissions) } } + +// This will really really use the API to place an order +// If you're going to test this, make sure you're willing to place real orders on the exchange +func TestSubmitOrder(t *testing.T) { + b.SetDefaults() + TestSetup(t) + + if b.APIKey == "" || b.APISecret == "" || + b.APIKey == "Key" || b.APISecret == "Secret" || + !canPlaceOrders { + t.Skip() + } + var p = pair.CurrencyPair{ + Delimiter: "", + FirstCurrency: symbol.BTC, + SecondCurrency: symbol.LTC, + } + response, err := b.SubmitExchangeOrder(p, exchange.Buy, exchange.Market, 1, 1, "clientId") + if err != nil || !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } +} diff --git a/exchanges/bitflyer/bitflyer_types.go b/exchanges/bitflyer/bitflyer_types.go index 3dd6c3e8..bdbe3523 100644 --- a/exchanges/bitflyer/bitflyer_types.go +++ b/exchanges/bitflyer/bitflyer_types.go @@ -278,3 +278,14 @@ type CollateralHistory struct { Reason string `json:"reason_code"` Date string `json:"date"` } + +// NewOrder to send a new order +type NewOrder struct { + ProductCode string `json:"product_code"` + ChildOrderType string `json:"child_order_type"` + Side string `json:"side"` + Price float64 `json:"price"` + Size float64 `json:"size"` + MinuteToExpire float64 `json:"minute_to_expire"` + TimeInForce string `json:"time_in_force"` +} diff --git a/exchanges/bitflyer/bitflyer_wrapper.go b/exchanges/bitflyer/bitflyer_wrapper.go index 17604d2a..acbd3885 100644 --- a/exchanges/bitflyer/bitflyer_wrapper.go +++ b/exchanges/bitflyer/bitflyer_wrapper.go @@ -153,8 +153,10 @@ func (b *Bitflyer) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([] } // SubmitExchangeOrder submits a new order -func (b *Bitflyer) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func (b *Bitflyer) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + + return submitOrderResponse, errors.New("not yet implemented") } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/bithumb/bithumb_test.go b/exchanges/bithumb/bithumb_test.go index dfcee7b0..3f53ab4a 100644 --- a/exchanges/bithumb/bithumb_test.go +++ b/exchanges/bithumb/bithumb_test.go @@ -4,14 +4,16 @@ import ( "testing" "github.com/thrasher-/gocryptotrader/config" + "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" exchange "github.com/thrasher-/gocryptotrader/exchanges" ) // Please supply your own keys here for due diligence testing const ( - testAPIKey = "" - testAPISecret = "" + testAPIKey = "" + testAPISecret = "" + canPlaceOrders = false ) var b Bithumb @@ -281,3 +283,25 @@ func TestFormatWithdrawPermissions(t *testing.T) { t.Errorf("Expected: %s, Recieved: %s", expectedResult, withdrawPermissions) } } + +// This will really really use the API to place an order +// If you're going to test this, make sure you're willing to place real orders on the exchange +func TestSubmitOrder(t *testing.T) { + b.SetDefaults() + TestSetup(t) + + if b.APIKey == "" || b.APISecret == "" || + b.APIKey == "Key" || b.APISecret == "Secret" || + !canPlaceOrders { + t.Skip() + } + var p = pair.CurrencyPair{ + Delimiter: "", + FirstCurrency: symbol.BTC, + SecondCurrency: symbol.LTC, + } + response, err := b.SubmitExchangeOrder(p, exchange.Buy, exchange.Market, 1, 1, "clientId") + if err != nil || !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } +} diff --git a/exchanges/bithumb/bithumb_wrapper.go b/exchanges/bithumb/bithumb_wrapper.go index 19f4107a..b528e59a 100644 --- a/exchanges/bithumb/bithumb_wrapper.go +++ b/exchanges/bithumb/bithumb_wrapper.go @@ -2,6 +2,7 @@ package bithumb import ( "errors" + "fmt" "log" "sync" @@ -140,8 +141,29 @@ func (b *Bithumb) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]e } // SubmitExchangeOrder submits a new order -func (b *Bithumb) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func (b *Bithumb) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + var err error + var orderID string + if side == exchange.Buy { + var result MarketBuy + result, err = b.MarketBuyOrder(p.FirstCurrency.String(), amount) + orderID = result.OrderID + } else if side == exchange.Sell { + var result MarketSell + result, err = b.MarketSellOrder(p.FirstCurrency.String(), amount) + orderID = result.OrderID + } + + if orderID != "" { + submitOrderResponse.OrderID = fmt.Sprintf("%v", orderID) + } + + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/bitmex/bitmex_parameters.go b/exchanges/bitmex/bitmex_parameters.go index accd4b25..2216a01b 100644 --- a/exchanges/bitmex/bitmex_parameters.go +++ b/exchanges/bitmex/bitmex_parameters.go @@ -286,7 +286,7 @@ type OrderNewParams struct { // DisplayQty - [Optional] quantity to display in the book. Use 0 for a fully // hidden order. - DisplayQty int32 `json:"displayQty,omitempty"` + DisplayQty float64 `json:"displayQty,omitempty"` // ExecInst - [Optional] execution instructions. Valid options: // ParticipateDoNotInitiate, AllOrNone, MarkPrice, IndexPrice, LastPrice, @@ -303,7 +303,7 @@ type OrderNewParams struct { OrdType string `json:"ordType,omitempty"` //OrderQty Order quantity in units of the instrument (i.e. contracts). - OrderQty int32 `json:"orderQty,omitempty"` + OrderQty float64 `json:"orderQty,omitempty"` // PegOffsetValue - [Optional] trailing offset from the current price for // 'Stop', 'StopLimit', 'MarketIfTouched', and 'LimitIfTouched' orders; use a diff --git a/exchanges/bitmex/bitmex_test.go b/exchanges/bitmex/bitmex_test.go index a2a86539..1954f6d6 100644 --- a/exchanges/bitmex/bitmex_test.go +++ b/exchanges/bitmex/bitmex_test.go @@ -6,14 +6,16 @@ import ( "time" "github.com/thrasher-/gocryptotrader/config" + "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" exchange "github.com/thrasher-/gocryptotrader/exchanges" ) // Please supply your own keys here for due diligence testing const ( - testAPIKey = "" - testAPISecret = "" + testAPIKey = "" + testAPISecret = "" + canPlaceOrders = false ) var b Bitmex @@ -461,3 +463,25 @@ func TestFormatWithdrawPermissions(t *testing.T) { t.Errorf("Expected: %s, Recieved: %s", expectedResult, withdrawPermissions) } } + +// This will really really use the API to place an order +// If you're going to test this, make sure you're willing to place real orders on the exchange +func TestSubmitOrder(t *testing.T) { + b.SetDefaults() + TestSetup(t) + + if b.APIKey == "" || b.APISecret == "" || + b.APIKey == "Key" || b.APISecret == "Secret" || + !canPlaceOrders { + t.Skip() + } + var p = pair.CurrencyPair{ + Delimiter: "", + FirstCurrency: symbol.XBT, + SecondCurrency: symbol.USD, + } + response, err := b.SubmitExchangeOrder(p, exchange.Buy, exchange.Market, 1, 1, "clientId") + if err != nil || !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } +} diff --git a/exchanges/bitmex/bitmex_wrapper.go b/exchanges/bitmex/bitmex_wrapper.go index 172ddb65..c188715c 100644 --- a/exchanges/bitmex/bitmex_wrapper.go +++ b/exchanges/bitmex/bitmex_wrapper.go @@ -144,8 +144,29 @@ func (b *Bitmex) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]ex } // 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") +func (b *Bitmex) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + var orderNewParams = OrderNewParams{ + OrdType: side.ToString(), + Symbol: p.Pair().String(), + OrderQty: amount, + Side: side.ToString(), + } + + if orderType == exchange.Limit { + orderNewParams.Price = price + } + + response, err := b.CreateOrder(orderNewParams) + if response.OrderID != "" { + submitOrderResponse.OrderID = response.OrderID + } + + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/bitstamp/bitstamp.go b/exchanges/bitstamp/bitstamp.go index 53298a2f..6a3376e8 100644 --- a/exchanges/bitstamp/bitstamp.go +++ b/exchanges/bitstamp/bitstamp.go @@ -100,6 +100,10 @@ func (b *Bitstamp) Setup(exch config.ExchangeConfig) { b.BaseCurrencies = common.SplitStrings(exch.BaseCurrencies, ",") b.AvailablePairs = common.SplitStrings(exch.AvailablePairs, ",") b.EnabledPairs = common.SplitStrings(exch.EnabledPairs, ",") + b.APIKey = exch.APIKey + b.APISecret = exch.APISecret + b.SetAPIKeys(exch.APIKey, exch.APISecret, b.ClientID, false) + b.AuthenticatedAPISupport = true err := b.SetCurrencyPairFormat() if err != nil { log.Fatal(err) @@ -612,5 +616,7 @@ func (b *Bitstamp) SendAuthenticatedHTTPRequest(path string, v2 bool, values url headers := make(map[string]string) headers["Content-Type"] = "application/x-www-form-urlencoded" - return b.SendPayload("POST", path, headers, strings.NewReader(values.Encode()), result, true, b.Verbose) + encodedValues := values.Encode() + readerValues := strings.NewReader(encodedValues) + return b.SendPayload("POST", path, headers, readerValues, result, true, b.Verbose) } diff --git a/exchanges/bitstamp/bitstamp_test.go b/exchanges/bitstamp/bitstamp_test.go index 11633cc6..b6ca82d3 100644 --- a/exchanges/bitstamp/bitstamp_test.go +++ b/exchanges/bitstamp/bitstamp_test.go @@ -5,6 +5,7 @@ import ( "testing" "time" + "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" "github.com/thrasher-/gocryptotrader/exchanges" @@ -13,9 +14,10 @@ import ( // Please add your private keys and customerID for better tests const ( - apiKey = "" - apiSecret = "" - customerID = "" + apiKey = "" + apiSecret = "" + customerID = "" + canPlaceOrders = false ) var b Bitstamp @@ -47,9 +49,11 @@ func TestSetup(t *testing.T) { if err != nil { t.Error("Test Failed - Bitstamp Setup() init error") } + bConfig.APIKey = apiKey + bConfig.APISecret = apiSecret b.Setup(bConfig) - if !b.IsEnabled() || b.AuthenticatedAPISupport || b.RESTPollingDelay != time.Duration(10) || + if !b.IsEnabled() || b.RESTPollingDelay != time.Duration(10) || b.Verbose || b.Websocket.IsEnabled() || len(b.BaseCurrencies) < 1 || len(b.AvailablePairs) < 1 || len(b.EnabledPairs) < 1 { t.Error("Test Failed - Bitstamp Setup values not set correctly") @@ -248,7 +252,10 @@ func TestGetOpenOrders(t *testing.T) { func TestGetOrderStatus(t *testing.T) { t.Parallel() - + if b.APIKey == "" || b.APISecret == "" || + b.APIKey == "Key" || b.APISecret == "Secret" { + t.Skip() + } _, err := b.GetOrderStatus(1337) if err == nil { t.Error("Test Failed - GetOpenOrders() error") @@ -275,7 +282,10 @@ func TestCancelAllOrders(t *testing.T) { func TestPlaceOrder(t *testing.T) { t.Parallel() - + if b.APIKey == "" || b.APISecret == "" || + b.APIKey == "Key" || b.APISecret == "Secret" { + t.Skip() + } _, err := b.PlaceOrder("btcusd", 0.01, 1, true, true) if err == nil { t.Error("Test Failed - PlaceOrder() error") @@ -297,6 +307,10 @@ func TestGetWithdrawalRequests(t *testing.T) { func TestCryptoWithdrawal(t *testing.T) { t.Parallel() + if b.APIKey == "" || b.APISecret == "" || + b.APIKey == "Key" || b.APISecret == "Secret" { + t.Skip() + } _, err := b.CryptoWithdrawal(0, "bla", "btc", "", true) if err == nil { @@ -323,8 +337,12 @@ func TestGetUnconfirmedBitcoinDeposits(t *testing.T) { } func TestTransferAccountBalance(t *testing.T) { - t.Parallel() + t.Parallel() + if b.APIKey == "" || b.APISecret == "" || + b.APIKey == "Key" || b.APISecret == "Secret" { + t.Skip() + } _, err := b.TransferAccountBalance(1, "", "", true) if err == nil { t.Error("Test Failed - TransferAccountBalance() error", err) @@ -346,3 +364,25 @@ func TestFormatWithdrawPermissions(t *testing.T) { t.Errorf("Expected: %s, Recieved: %s", expectedResult, withdrawPermissions) } } + +// This will really really use the API to place an order +// If you're going to test this, make sure you're willing to place real orders on the exchange +func TestSubmitOrder(t *testing.T) { + b.SetDefaults() + TestSetup(t) + + if b.APIKey == "" || b.APISecret == "" || + b.APIKey == "Key" || b.APISecret == "Secret" || + !canPlaceOrders { + t.Skip() + } + var p = pair.CurrencyPair{ + Delimiter: "", + FirstCurrency: symbol.BTC, + SecondCurrency: symbol.USD, + } + response, err := b.SubmitExchangeOrder(p, exchange.Buy, exchange.Market, 1, 1, "clientId") + if err != nil || !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } +} diff --git a/exchanges/bitstamp/bitstamp_wrapper.go b/exchanges/bitstamp/bitstamp_wrapper.go index d9649718..2036dd4e 100644 --- a/exchanges/bitstamp/bitstamp_wrapper.go +++ b/exchanges/bitstamp/bitstamp_wrapper.go @@ -2,6 +2,7 @@ package bitstamp import ( "errors" + "fmt" "log" "strings" "sync" @@ -165,8 +166,21 @@ func (b *Bitstamp) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([] } // SubmitExchangeOrder submits a new order -func (b *Bitstamp) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func (b *Bitstamp) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + buy := side == exchange.Buy + market := orderType == exchange.Market + response, err := b.PlaceOrder(p.Pair().String(), price, amount, buy, market) + + if response.ID > 0 { + submitOrderResponse.OrderID = fmt.Sprintf("%v", response.ID) + } + + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/bittrex/bittrex_test.go b/exchanges/bittrex/bittrex_test.go index 34b7f0a8..fdbe01db 100644 --- a/exchanges/bittrex/bittrex_test.go +++ b/exchanges/bittrex/bittrex_test.go @@ -5,14 +5,16 @@ import ( "time" "github.com/thrasher-/gocryptotrader/config" + "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" exchange "github.com/thrasher-/gocryptotrader/exchanges" ) // Please supply you own test keys here to run better tests. const ( - apiKey = "Testy" - apiSecret = "TestyTesty" + apiKey = "" + apiSecret = "" + canPlaceOrders = false ) var b Bittrex @@ -31,10 +33,13 @@ func TestSetup(t *testing.T) { if err != nil { t.Error("Test Failed - Bittrex Setup() init error") } + bConfig.APIKey = apiKey + bConfig.APISecret = apiSecret + bConfig.AuthenticatedAPISupport = true b.Setup(bConfig) - if !b.IsEnabled() || b.AuthenticatedAPISupport || + if !b.IsEnabled() || b.RESTPollingDelay != time.Duration(10) || b.Verbose || b.Websocket.IsEnabled() || len(b.BaseCurrencies) < 1 || len(b.AvailablePairs) < 1 || len(b.EnabledPairs) < 1 { @@ -327,3 +332,25 @@ func TestFormatWithdrawPermissions(t *testing.T) { t.Errorf("Expected: %s, Recieved: %s", expectedResult, withdrawPermissions) } } + +// This will really really use the API to place an order +// If you're going to test this, make sure you're willing to place real orders on the exchange +func TestSubmitOrder(t *testing.T) { + b.SetDefaults() + TestSetup(t) + + if b.APIKey == "" || b.APISecret == "" || + b.APIKey == "Key" || b.APISecret == "Secret" || + !canPlaceOrders { + t.Skip() + } + var p = pair.CurrencyPair{ + Delimiter: "-", + FirstCurrency: symbol.BTC, + SecondCurrency: symbol.LTC, + } + response, err := b.SubmitExchangeOrder(p, exchange.Buy, exchange.Limit, 1, 1, "clientId") + if err != nil || !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } +} diff --git a/exchanges/bittrex/bittrex_types.go b/exchanges/bittrex/bittrex_types.go index 754dc0bc..c1ea773f 100644 --- a/exchanges/bittrex/bittrex_types.go +++ b/exchanges/bittrex/bittrex_types.go @@ -150,7 +150,7 @@ type DepositAddress struct { type UUID struct { Success bool `json:"success"` Message string `json:"message"` - Result []struct { + Result struct { ID string `json:"uuid"` } `json:"result"` } diff --git a/exchanges/bittrex/bittrex_wrapper.go b/exchanges/bittrex/bittrex_wrapper.go index 4f65ff26..0e887513 100644 --- a/exchanges/bittrex/bittrex_wrapper.go +++ b/exchanges/bittrex/bittrex_wrapper.go @@ -169,8 +169,31 @@ func (b *Bittrex) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]e } // SubmitExchangeOrder submits a new order -func (b *Bittrex) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func (b *Bittrex) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + buy := side == exchange.Buy + var response UUID + var err error + + if orderType != exchange.Limit { + return submitOrderResponse, errors.New("not supported on exchange") + } + + if buy { + response, err = b.PlaceBuyLimit(p.Pair().String(), amount, price) + } else { + response, err = b.PlaceSellLimit(p.Pair().String(), amount, price) + } + + if response.Result.ID != "" { + submitOrderResponse.OrderID = response.Result.ID + } + + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/btcc/btcc_wrapper.go b/exchanges/btcc/btcc_wrapper.go index 69b15c98..05acf2f6 100644 --- a/exchanges/btcc/btcc_wrapper.go +++ b/exchanges/btcc/btcc_wrapper.go @@ -151,8 +151,10 @@ func (b *BTCC) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]exch } // SubmitExchangeOrder submits a new order -func (b *BTCC) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func (b *BTCC) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + + return submitOrderResponse, errors.New("not yet implemented") } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/btcmarkets/btcmarkets_test.go b/exchanges/btcmarkets/btcmarkets_test.go index f4601adb..cec29052 100644 --- a/exchanges/btcmarkets/btcmarkets_test.go +++ b/exchanges/btcmarkets/btcmarkets_test.go @@ -14,8 +14,9 @@ var b BTCMarkets // Please supply your own keys here to do better tests const ( - apiKey = "" - apiSecret = "" + apiKey = "" + apiSecret = "" + canPlaceOrders = false ) func TestSetDefaults(t *testing.T) { @@ -154,7 +155,7 @@ func TestGetExchangeFundTransferHistory(t *testing.T) { func TestSubmitExchangeOrder(t *testing.T) { p := pair.NewCurrencyPair("LTC", "AUD") - _, err := b.SubmitExchangeOrder(p, exchange.OrderSideSell(), exchange.OrderTypeMarket(), 0, 0.0, "testID001") + _, err := b.SubmitExchangeOrder(p, exchange.Sell, exchange.Market, 0, 0.0, "testID001") if err == nil { t.Error("Test failed - SubmitExchangeOrder() error", err) } @@ -308,3 +309,25 @@ func TestFormatWithdrawPermissions(t *testing.T) { t.Errorf("Expected: %s, Recieved: %s", expectedResult, withdrawPermissions) } } + +// This will really really use the API to place an order +// If you're going to test this, make sure you're willing to place real orders on the exchange +func TestSubmitOrder(t *testing.T) { + b.SetDefaults() + TestSetup(t) + + if b.APIKey == "" || b.APISecret == "" || + b.APIKey == "Key" || b.APISecret == "Secret" || + !canPlaceOrders { + t.Skip() + } + var p = pair.CurrencyPair{ + Delimiter: "-", + FirstCurrency: symbol.BTC, + SecondCurrency: symbol.LTC, + } + response, err := b.SubmitExchangeOrder(p, exchange.Buy, exchange.Limit, 1, 1, "clientId") + if err != nil || !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } +} diff --git a/exchanges/btcmarkets/btcmarkets_wrapper.go b/exchanges/btcmarkets/btcmarkets_wrapper.go index 77bed933..878adf38 100644 --- a/exchanges/btcmarkets/btcmarkets_wrapper.go +++ b/exchanges/btcmarkets/btcmarkets_wrapper.go @@ -2,6 +2,7 @@ package btcmarkets import ( "errors" + "fmt" "log" "sync" @@ -153,8 +154,19 @@ func (b *BTCMarkets) GetExchangeHistory(p pair.CurrencyPair, assetType string) ( } // SubmitExchangeOrder submits a new order -func (b *BTCMarkets) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return b.NewOrder(p.FirstCurrency.Upper().String(), p.SecondCurrency.Upper().String(), price, amount, side.Format(b.GetName()), orderType.Format(b.GetName()), clientID) +func (b *BTCMarkets) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + response, err := b.NewOrder(p.FirstCurrency.Upper().String(), p.SecondCurrency.Upper().String(), price, amount, side.ToString(), orderType.ToString(), clientID) + + if response > 0 { + submitOrderResponse.OrderID = fmt.Sprintf("%v", response) + } + + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/coinbasepro/coinbasepro_test.go b/exchanges/coinbasepro/coinbasepro_test.go index 4cff5d05..2e2ececd 100644 --- a/exchanges/coinbasepro/coinbasepro_test.go +++ b/exchanges/coinbasepro/coinbasepro_test.go @@ -1,10 +1,12 @@ package coinbasepro import ( + "fmt" "testing" "time" "github.com/thrasher-/gocryptotrader/config" + "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" exchange "github.com/thrasher-/gocryptotrader/exchanges" ) @@ -13,9 +15,10 @@ var c CoinbasePro // Please supply your APIKeys here for better testing const ( - apiKey = "" - apiSecret = "" - clientID = "" //passphrase you made at API CREATION + apiKey = "" + apiSecret = "" + clientID = "" //passphrase you made at API CREATION + canPlaceOrders = false ) func TestSetDefaults(t *testing.T) { @@ -30,7 +33,9 @@ func TestSetup(t *testing.T) { if err != nil { t.Error("Test Failed - coinbasepro Setup() init error") } - + gdxConfig.APIKey = apiKey + gdxConfig.APISecret = apiSecret + gdxConfig.AuthenticatedAPISupport = true c.Setup(gdxConfig) } @@ -402,3 +407,25 @@ func TestFormatWithdrawPermissions(t *testing.T) { t.Errorf("Expected: %s, Recieved: %s", expectedResult, withdrawPermissions) } } + +// This will really really use the API to place an order +// If you're going to test this, make sure you're willing to place real orders on the exchange +func TestSubmitOrder(t *testing.T) { + c.SetDefaults() + TestSetup(t) + + if c.APIKey == "" || c.APISecret == "" || + c.APIKey == "Key" || c.APISecret == "Secret" || + !canPlaceOrders { + t.Skip(fmt.Sprintf("ApiKey: %s. Can Place others: %v", c.APIKey, canPlaceOrders)) + } + var p = pair.CurrencyPair{ + Delimiter: "-", + FirstCurrency: symbol.BTC, + SecondCurrency: symbol.LTC, + } + response, err := c.SubmitExchangeOrder(p, exchange.Buy, exchange.Limit, 1, 1, "clientId") + if err != nil || !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } +} diff --git a/exchanges/coinbasepro/coinbasepro_wrapper.go b/exchanges/coinbasepro/coinbasepro_wrapper.go index ba8620aa..12301970 100644 --- a/exchanges/coinbasepro/coinbasepro_wrapper.go +++ b/exchanges/coinbasepro/coinbasepro_wrapper.go @@ -144,8 +144,28 @@ func (c *CoinbasePro) GetExchangeHistory(p pair.CurrencyPair, assetType string) } // SubmitExchangeOrder submits a new order -func (c *CoinbasePro) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func (c *CoinbasePro) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + var response string + var err error + if orderType == exchange.Market { + response, err = c.PlaceMarginOrder("", amount, amount, side.ToString(), p.Pair().String(), "") + + } else if orderType == exchange.Limit { + response, err = c.PlaceLimitOrder("", price, amount, side.ToString(), "", "", p.Pair().String(), "", false) + } else { + err = errors.New("not supported") + } + + if response != "" { + submitOrderResponse.OrderID = response + } + + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/coinut/coinut.go b/exchanges/coinut/coinut.go index 2ad3397c..f7be236d 100644 --- a/exchanges/coinut/coinut.go +++ b/exchanges/coinut/coinut.go @@ -80,7 +80,7 @@ func (c *COINUT) Setup(exch config.ExchangeConfig) { } else { c.Enabled = true c.AuthenticatedAPISupport = exch.AuthenticatedAPISupport - c.SetAPIKeys(exch.APIKey, exch.APISecret, exch.ClientID, true) + c.SetAPIKeys(exch.APIKey, exch.APISecret, exch.ClientID, false) c.SetHTTPClientTimeout(exch.HTTPTimeout) c.SetHTTPClientUserAgent(exch.HTTPUserAgent) c.RESTPollingDelay = exch.RESTPollingDelay @@ -171,15 +171,27 @@ func (c *COINUT) NewOrder(instrumentID int, quantity, price float64, buy bool, o var result interface{} params := make(map[string]interface{}) params["inst_id"] = instrumentID - params["price"] = price - params["qty"] = quantity + if price > 0 { + params["price"] = fmt.Sprintf("%v", price) + } + params["qty"] = fmt.Sprintf("%v", quantity) params["side"] = "BUY" if !buy { params["side"] = "SELL" } params["client_ord_id"] = orderID - return result, c.SendHTTPRequest(coinutOrder, params, true, &result) + err := c.SendHTTPRequest(coinutOrder, params, true, &result) + if _, ok := result.(OrderRejectResponse); ok { + return result.(OrderRejectResponse), err + } + if _, ok := result.(OrderFilledResponse); ok { + return result.(OrderFilledResponse), err + } + if _, ok := result.(OrdersBase); ok { + return result.(OrdersBase), err + } + return result, err } // NewOrders places multiple orders on the exchange diff --git a/exchanges/coinut/coinut_test.go b/exchanges/coinut/coinut_test.go index f79662f9..efd4136d 100644 --- a/exchanges/coinut/coinut_test.go +++ b/exchanges/coinut/coinut_test.go @@ -1,10 +1,12 @@ package coinut import ( + "fmt" "testing" "time" "github.com/thrasher-/gocryptotrader/config" + "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" exchange "github.com/thrasher-/gocryptotrader/exchanges" ) @@ -13,8 +15,9 @@ var c COINUT // Please supply your own keys here to do better tests const ( - apiKey = "" - apiSecret = "" + apiKey = "" + apiSecret = "" + canPlaceOrders = false ) func TestSetDefaults(t *testing.T) { @@ -28,10 +31,13 @@ func TestSetup(t *testing.T) { if err != nil { t.Error("Test Failed - Coinut Setup() init error") } + bConfig.AuthenticatedAPISupport = true + bConfig.APISecret = apiSecret + bConfig.Verbose = true c.Setup(bConfig) - if !c.IsEnabled() || c.AuthenticatedAPISupport || - c.RESTPollingDelay != time.Duration(10) || c.Verbose || + if !c.IsEnabled() || + c.RESTPollingDelay != time.Duration(10) || c.Websocket.IsEnabled() || len(c.BaseCurrencies) < 1 || len(c.AvailablePairs) < 1 || len(c.EnabledPairs) < 1 { t.Error("Test Failed - Coinut Setup values not set correctly") @@ -186,3 +192,26 @@ func TestFormatWithdrawPermissions(t *testing.T) { t.Errorf("Expected: %s, Recieved: %s", expectedResult, withdrawPermissions) } } + +// This will really really use the API to place an order +// If you're going to test this, make sure you're willing to place real orders on the exchange +func TestSubmitOrder(t *testing.T) { + c.SetDefaults() + TestSetup(t) + c.Verbose = true + + if c.APISecret == "" || + c.APISecret == "Secret" || + !canPlaceOrders { + t.Skip(fmt.Sprintf("ApiKey: %s. Can place orders: %v", c.APIKey, canPlaceOrders)) + } + var p = pair.CurrencyPair{ + Delimiter: "", + FirstCurrency: symbol.BTC, + SecondCurrency: symbol.USD, + } + response, err := c.SubmitExchangeOrder(p, exchange.Buy, exchange.Limit, 1, 10, "1234234") + if err != nil || !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } +} diff --git a/exchanges/coinut/coinut_wrapper.go b/exchanges/coinut/coinut_wrapper.go index 2ae71d3f..f931e5fe 100644 --- a/exchanges/coinut/coinut_wrapper.go +++ b/exchanges/coinut/coinut_wrapper.go @@ -2,7 +2,9 @@ package coinut import ( "errors" + "fmt" "log" + "strconv" "sync" "github.com/thrasher-/gocryptotrader/common" @@ -141,8 +143,52 @@ func (c *COINUT) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]ex } // SubmitExchangeOrder submits a new order -func (c *COINUT) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func (c *COINUT) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + var err error + var APIresponse interface{} + isBuyOrder := side == exchange.Buy + clientIDInt, err := strconv.ParseUint(clientID, 0, 32) + clientIDUint := uint32(clientIDInt) + + if err != nil { + return submitOrderResponse, err + } + // Need to get the ID of the currency sent + instruments, err := c.GetInstruments() + if err != nil { + return submitOrderResponse, err + } + + currencyArray := instruments.Instruments[p.Pair().String()] + currencyID := currencyArray[0].InstID + + if orderType == exchange.Limit { + APIresponse, err = c.NewOrder(currencyID, amount, price, isBuyOrder, clientIDUint) + } else if orderType == exchange.Market { + APIresponse, err = c.NewOrder(currencyID, amount, 0, isBuyOrder, clientIDUint) + } else { + return submitOrderResponse, errors.New("unsupported order type") + } + + switch APIresponse.(type) { + case OrdersBase: + orderResult := APIresponse.(OrdersBase) + submitOrderResponse.OrderID = fmt.Sprintf("%v", orderResult.OrderID) + case OrderFilledResponse: + orderResult := APIresponse.(OrderFilledResponse) + submitOrderResponse.OrderID = fmt.Sprintf("%v", orderResult.Order.OrderID) + case OrderRejectResponse: + orderResult := APIresponse.(OrderRejectResponse) + submitOrderResponse.OrderID = fmt.Sprintf("%v", orderResult.OrderID) + err = fmt.Errorf("OrderID: %v was rejected: %v", orderResult.OrderID, orderResult.Reasons) + } + + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/exchange.go b/exchanges/exchange.go index a3454683..be026d91 100644 --- a/exchanges/exchange.go +++ b/exchanges/exchange.go @@ -67,6 +67,12 @@ const ( Contact InternationalBankTransactionType = "contact" ) +// SubmitOrderResponse is what is returned after submitting an order to an exchange +type SubmitOrderResponse struct { + IsOrderPlaced bool + OrderID string +} + // FeeBuilder is the type which holds all parameters required to calculate a fee for an exchange type FeeBuilder struct { FeeType FeeType @@ -246,7 +252,7 @@ type IBotExchange interface { SupportsWithdrawPermissions(permissions uint32) bool GetExchangeFundTransferHistory() ([]FundHistory, error) - SubmitExchangeOrder(p pair.CurrencyPair, side OrderSide, orderType OrderType, amount, price float64, clientID string) (int64, error) + SubmitExchangeOrder(p pair.CurrencyPair, side OrderSide, orderType OrderType, amount, price float64, clientID string) (SubmitOrderResponse, error) ModifyExchangeOrder(orderID int64, modify ModifyOrder) (int64, error) CancelExchangeOrder(orderID int64) error CancelAllExchangeOrders() error @@ -729,65 +735,32 @@ type Format struct { // Formatting contain a range of exchanges formatting type Formatting []Format -// formats is a quick formatting list for generic parameters -var formats = Formatting{ - Format{ - ExchangeName: "BTC Markets", - OrderType: map[string]string{ - "Limit": "Limit", - "Market": "Market", - }, - OrderSide: map[string]string{ - "Buy": "Bid", - "Sell": "Ask", - }, - }, -} - // OrderType enforces a standard for Ordertypes across the code base type OrderType string -// Format changes the ordertype to the exchange standard and returns a string -func (o OrderType) Format(exchangeName string) string { - for _, format := range formats { - if format.ExchangeName == exchangeName { - return format.OrderType[string(o)] - } - } - return "" -} +// OrderType ...types +const ( + Limit OrderType = "Limit" + Market OrderType = "Market" +) -// OrderTypeLimit returns an OrderType limit order -func OrderTypeLimit() OrderType { - return "Limit" -} - -// OrderTypeMarket returns an OrderType Market order -func OrderTypeMarket() OrderType { - return "Market" +// ToString changes the ordertype to the exchange standard and returns a string +func (o OrderType) ToString() string { + return fmt.Sprintf("%v", o) } // OrderSide enforces a standard for OrderSides across the code base type OrderSide string -// Format changes the ordertype to the exchange standard and returns a string -func (o OrderSide) Format(exchangeName string) string { - for _, format := range formats { - if format.ExchangeName == exchangeName { - return format.OrderSide[string(o)] - } - } - return "" -} +// OrderSide types +const ( + Buy OrderSide = "Buy" + Sell OrderSide = "Sell" +) -// OrderSideBuy returns an OrderSide buy order -func OrderSideBuy() OrderSide { - return "Buy" -} - -// OrderSideSell returns an OrderSide Sell order -func OrderSideSell() OrderSide { - return "Sell" +// ToString changes the ordertype to the exchange standard and returns a string +func (o OrderSide) ToString() string { + return fmt.Sprintf("%v", o) } // SetAPIURL sets configuration API URL for an exchange @@ -882,7 +855,7 @@ func (e *Base) FormatWithdrawPermissions() string { case WithdrawFiatViaWebsiteOnly: services = append(services, WithdrawFiatViaWebsiteOnlyText) default: - services = append(services, fmt.Sprintf("%s[%v]", UnknownWithdrawalTypeText, check)) + services = append(services, fmt.Sprintf("%s[1<<%v]", UnknownWithdrawalTypeText, i)) } } } diff --git a/exchanges/exchange_test.go b/exchanges/exchange_test.go index 72e7d183..172c1eaf 100644 --- a/exchanges/exchange_test.go +++ b/exchanges/exchange_test.go @@ -883,10 +883,48 @@ func TestFormatWithdrawPermissions(t *testing.T) { } UAC := Base{Name: "ANX"} - UAC.APIWithdrawPermissions = AutoWithdrawCrypto | AutoWithdrawCryptoWithAPIPermission + UAC.APIWithdrawPermissions = AutoWithdrawCrypto | + AutoWithdrawCryptoWithAPIPermission | + AutoWithdrawCryptoWithSetup | + WithdrawCryptoWith2FA | + WithdrawCryptoWithSMS | + WithdrawCryptoWithEmail | + WithdrawCryptoWithWebsiteApproval | + WithdrawCryptoWithAPIPermission | + AutoWithdrawFiat | + AutoWithdrawFiatWithAPIPermission | + AutoWithdrawFiatWithSetup | + WithdrawFiatWith2FA | + WithdrawFiatWithSMS | + WithdrawFiatWithEmail | + WithdrawFiatWithWebsiteApproval | + WithdrawFiatWithAPIPermission | + WithdrawCryptoViaWebsiteOnly | + WithdrawFiatViaWebsiteOnly | + 1<<18 withdrawPermissions := UAC.FormatWithdrawPermissions() - if withdrawPermissions != AutoWithdrawCryptoText+" & "+AutoWithdrawCryptoWithAPIPermissionText { + if withdrawPermissions != "AUTO WITHDRAW CRYPTO & AUTO WITHDRAW CRYPTO WITH API PERMISSION & AUTO WITHDRAW CRYPTO WITH SETUP & WITHDRAW CRYPTO WITH 2FA & WITHDRAW CRYPTO WITH SMS & WITHDRAW CRYPTO WITH EMAIL & WITHDRAW CRYPTO WITH WEBSITE APPROVAL & WITHDRAW CRYPTO WITH API PERMISSION & AUTO WITHDRAW FIAT & AUTO WITHDRAW FIAT WITH API PERMISSION & AUTO WITHDRAW FIAT WITH SETUP & WITHDRAW FIAT WITH 2FA & WITHDRAW FIAT WITH SMS & WITHDRAW FIAT WITH EMAIL & WITHDRAW FIAT WITH WEBSITE APPROVAL & WITHDRAW FIAT WITH API PERMISSION & WITHDRAW CRYPTO VIA WEBSITE ONLY & WITHDRAW FIAT VIA WEBSITE ONLY & UNKNOWN[1<<18]" { t.Errorf("Expected: %s, Recieved: %s", AutoWithdrawCryptoText+" & "+AutoWithdrawCryptoWithAPIPermissionText, withdrawPermissions) } + UAC.APIWithdrawPermissions = NoAPIWithdrawalMethods + withdrawPermissions = UAC.FormatWithdrawPermissions() + + if withdrawPermissions != NoAPIWithdrawalMethodsText { + t.Errorf("Expected: %s, Recieved: %s", NoAPIWithdrawalMethodsText, withdrawPermissions) + } +} + +func TestOrderTypes(t *testing.T) { + var ot OrderType = "Mo'Money" + + if ot.ToString() != "Mo'Money" { + t.Errorf("test failed - unexpected string %s", ot.ToString()) + } + + var os OrderSide = "BUY" + + if os.ToString() != "BUY" { + t.Errorf("test failed - unexpected string %s", os.ToString()) + } } diff --git a/exchanges/exmo/exmo_test.go b/exchanges/exmo/exmo_test.go index 4e14fcc9..cca7dd5a 100644 --- a/exchanges/exmo/exmo_test.go +++ b/exchanges/exmo/exmo_test.go @@ -1,15 +1,18 @@ package exmo import ( + "fmt" "testing" + "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" exchange "github.com/thrasher-/gocryptotrader/exchanges" ) const ( - APIKey = "" - APISecret = "" + APIKey = "" + APISecret = "" + canPlaceOrders = false ) var ( @@ -245,3 +248,26 @@ func TestFormatWithdrawPermissions(t *testing.T) { t.Errorf("Expected: %s, Recieved: %s", expectedResult, withdrawPermissions) } } + +// This will really really use the API to place an order +// If you're going to test this, make sure you're willing to place real orders on the exchange +func TestSubmitOrder(t *testing.T) { + e.SetDefaults() + TestSetup(t) + e.Verbose = true + + if e.APISecret == "" || + e.APISecret == "Secret" || + !canPlaceOrders { + t.Skip(fmt.Sprintf("ApiKey: %s. Can place orders: %v", e.APIKey, canPlaceOrders)) + } + var p = pair.CurrencyPair{ + Delimiter: "_", + FirstCurrency: symbol.BTC, + SecondCurrency: symbol.USD, + } + response, err := e.SubmitExchangeOrder(p, exchange.Buy, exchange.Market, 1, 10, "1234234") + if err != nil || !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } +} diff --git a/exchanges/exmo/exmo_wrapper.go b/exchanges/exmo/exmo_wrapper.go index 8e64b583..3c078976 100644 --- a/exchanges/exmo/exmo_wrapper.go +++ b/exchanges/exmo/exmo_wrapper.go @@ -2,6 +2,7 @@ package exmo import ( "errors" + "fmt" "log" "strconv" "sync" @@ -176,8 +177,32 @@ func (e *EXMO) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]exch } // SubmitExchangeOrder submits a new order -func (e *EXMO) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func (e *EXMO) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + var oT string + if orderType == exchange.Limit { + return submitOrderResponse, errors.New("Unsupported order type") + } else if orderType == exchange.Market { + if side == exchange.Buy { + oT = "market_buy" + } else { + oT = "market_sell" + } + } else { + return submitOrderResponse, errors.New("Unsupported order type") + } + + response, err := e.CreateOrder(p.Pair().String(), oT, price, amount) + + if response > 0 { + submitOrderResponse.OrderID = fmt.Sprintf("%v", response) + } + + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/gateio/gateio_test.go b/exchanges/gateio/gateio_test.go index 23a85a5d..fff3e94a 100644 --- a/exchanges/gateio/gateio_test.go +++ b/exchanges/gateio/gateio_test.go @@ -1,9 +1,11 @@ package gateio import ( + "fmt" "testing" "github.com/thrasher-/gocryptotrader/config" + "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" exchange "github.com/thrasher-/gocryptotrader/exchanges" ) @@ -11,8 +13,9 @@ import ( // Please supply your own APIKEYS here for due diligence testing const ( - apiKey = "" - apiSecret = "" + apiKey = "" + apiSecret = "" + canPlaceOrders = false ) var g Gateio @@ -247,3 +250,26 @@ func TestFormatWithdrawPermissions(t *testing.T) { t.Errorf("Expected: %s, Recieved: %s", expectedResult, withdrawPermissions) } } + +// This will really really use the API to place an order +// If you're going to test this, make sure you're willing to place real orders on the exchange +func TestSubmitOrder(t *testing.T) { + g.SetDefaults() + TestSetup(t) + g.Verbose = true + + if g.APIKey == "" || g.APISecret == "" || + g.APIKey == "Key" || g.APISecret == "Secret" || + !canPlaceOrders { + t.Skip(fmt.Sprintf("ApiKey: %s. Can place orders: %v", g.APIKey, canPlaceOrders)) + } + var p = pair.CurrencyPair{ + Delimiter: "_", + FirstCurrency: symbol.LTC, + SecondCurrency: symbol.BTC, + } + response, err := g.SubmitExchangeOrder(p, exchange.Buy, exchange.Market, 1, 10, "1234234") + if err != nil || !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } +} diff --git a/exchanges/gateio/gateio_wrapper.go b/exchanges/gateio/gateio_wrapper.go index fb81e6ed..cdb88ed0 100644 --- a/exchanges/gateio/gateio_wrapper.go +++ b/exchanges/gateio/gateio_wrapper.go @@ -2,6 +2,7 @@ package gateio import ( "errors" + "fmt" "log" "sync" @@ -127,8 +128,34 @@ func (g *Gateio) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]ex } // SubmitExchangeOrder submits a new order -func (g *Gateio) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func (g *Gateio) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + var orderTypeFormat SpotNewOrderRequestParamsType + + if side == exchange.Buy { + orderTypeFormat = SpotNewOrderRequestParamsTypeBuy + } else { + orderTypeFormat = SpotNewOrderRequestParamsTypeSell + } + + var spotNewOrderRequestParams = SpotNewOrderRequestParams{ + Amount: amount, + Price: price, + Symbol: p.Pair().String(), + Type: orderTypeFormat, + } + + response, err := g.SpotNewOrder(spotNewOrderRequestParams) + + if response.OrderNumber > 0 { + submitOrderResponse.OrderID = fmt.Sprintf("%v", response) + } + + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/gemini/gemini_test.go b/exchanges/gemini/gemini_test.go index a6c2e71e..fab53488 100644 --- a/exchanges/gemini/gemini_test.go +++ b/exchanges/gemini/gemini_test.go @@ -1,10 +1,12 @@ package gemini import ( + "fmt" "net/url" "testing" "github.com/thrasher-/gocryptotrader/config" + "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" exchange "github.com/thrasher-/gocryptotrader/exchanges" ) @@ -21,6 +23,8 @@ const ( apiSecret2 = "" apiKeyRole2 = "" sessionHeartBeat2 = false + + canPlaceOrders = false ) func TestAddSession(t *testing.T) { @@ -320,3 +324,26 @@ func TestFormatWithdrawPermissions(t *testing.T) { t.Errorf("Expected: %s, Recieved: %s", expectedResult, withdrawPermissions) } } + +// This will really really use the API to place an order +// If you're going to test this, make sure you're willing to place real orders on the exchange +func TestSubmitOrder(t *testing.T) { + Session[1].SetDefaults() + TestSetup(t) + Session[1].Verbose = true + + if Session[1].APIKey == "" || Session[1].APISecret == "" || + Session[1].APIKey == "Key" || Session[1].APISecret == "Secret" || + !canPlaceOrders { + t.Skip(fmt.Sprintf("ApiKey: %s. Can place orders: %v", Session[1].APIKey, canPlaceOrders)) + } + var p = pair.CurrencyPair{ + Delimiter: "_", + FirstCurrency: symbol.LTC, + SecondCurrency: symbol.BTC, + } + response, err := Session[1].SubmitExchangeOrder(p, exchange.Buy, exchange.Market, 1, 10, "1234234") + if err != nil || !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } +} diff --git a/exchanges/gemini/gemini_wrapper.go b/exchanges/gemini/gemini_wrapper.go index 4c02d7a6..47f3ac7a 100644 --- a/exchanges/gemini/gemini_wrapper.go +++ b/exchanges/gemini/gemini_wrapper.go @@ -2,6 +2,7 @@ package gemini import ( "errors" + "fmt" "log" "net/url" "sync" @@ -127,8 +128,19 @@ func (g *Gemini) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]ex } // SubmitExchangeOrder submits a new order -func (g *Gemini) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func (g *Gemini) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + response, err := g.NewOrder(p.Pair().String(), amount, price, side.ToString(), orderType.ToString()) + + if response > 0 { + submitOrderResponse.OrderID = fmt.Sprintf("%v", response) + } + + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/hitbtc/hitbtc.go b/exchanges/hitbtc/hitbtc.go index b47fbc72..9f3f496d 100644 --- a/exchanges/hitbtc/hitbtc.go +++ b/exchanges/hitbtc/hitbtc.go @@ -37,7 +37,7 @@ const ( apiV2TradeHistory = "api/2/history/trades" apiV2FeeInfo = "api/2/trading/fee" orders = "order" - orderBuy = "buy" + orderBuy = "api/2/order" orderSell = "sell" orderCancel = "cancelOrder" orderMove = "moveOrder" @@ -413,30 +413,17 @@ func (h *HitBTC) GetAuthenticatedTradeHistory(currency, start, end string) (inte } // PlaceOrder places an order on the exchange -func (h *HitBTC) PlaceOrder(currency string, rate, amount float64, immediate, fillOrKill, buy bool) (OrderResponse, error) { +func (h *HitBTC) PlaceOrder(currency string, rate, amount float64, orderType, side string) (OrderResponse, error) { result := OrderResponse{} values := url.Values{} - var orderType string - if buy { - orderType = orderBuy - } else { - orderType = orderSell - } - - values.Set("currencyPair", currency) + values.Set("symbol", currency) values.Set("rate", strconv.FormatFloat(rate, 'f', -1, 64)) - values.Set("amount", strconv.FormatFloat(amount, 'f', -1, 64)) + values.Set("quantity", strconv.FormatFloat(amount, 'f', -1, 64)) + values.Set("side", side) + values.Set("price", strconv.FormatFloat(rate, 'f', -1, 64)) - if immediate { - values.Set("immediateOrCancel", "1") - } - - if fillOrKill { - values.Set("fillOrKill", "1") - } - - err := h.SendAuthenticatedHTTPRequest("POST", orderType, values, &result) + err := h.SendAuthenticatedHTTPRequest("POST", orderBuy, values, &result) if err != nil { return result, err diff --git a/exchanges/hitbtc/hitbtc_test.go b/exchanges/hitbtc/hitbtc_test.go index 08249c9f..31d35a4c 100644 --- a/exchanges/hitbtc/hitbtc_test.go +++ b/exchanges/hitbtc/hitbtc_test.go @@ -1,9 +1,11 @@ package hitbtc import ( + "fmt" "testing" "github.com/thrasher-/gocryptotrader/config" + "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" exchange "github.com/thrasher-/gocryptotrader/exchanges" ) @@ -13,8 +15,9 @@ var h HitBTC // Please supply your own APIKEYS here for due diligence testing const ( - apiKey = "" - apiSecret = "" + apiKey = "" + apiSecret = "" + canPlaceOrders = false ) func TestSetDefaults(t *testing.T) { @@ -172,3 +175,26 @@ func TestFormatWithdrawPermissions(t *testing.T) { t.Errorf("Expected: %s, Recieved: %s", expectedResult, withdrawPermissions) } } + +// This will really really use the API to place an order +// If you're going to test this, make sure you're willing to place real orders on the exchange +func TestSubmitOrder(t *testing.T) { + h.SetDefaults() + TestSetup(t) + h.Verbose = true + + if h.APIKey == "" || h.APISecret == "" || + h.APIKey == "Key" || h.APISecret == "Secret" || + !canPlaceOrders { + t.Skip(fmt.Sprintf("ApiKey: %s. Can place orders: %v", h.APIKey, canPlaceOrders)) + } + var p = pair.CurrencyPair{ + Delimiter: "", + FirstCurrency: symbol.DGD, + SecondCurrency: symbol.BTC, + } + response, err := h.SubmitExchangeOrder(p, exchange.Buy, exchange.Market, 1, 10, "1234234") + if err != nil || !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } +} diff --git a/exchanges/hitbtc/hitbtc_wrapper.go b/exchanges/hitbtc/hitbtc_wrapper.go index 479418d1..79ccbb4e 100644 --- a/exchanges/hitbtc/hitbtc_wrapper.go +++ b/exchanges/hitbtc/hitbtc_wrapper.go @@ -2,6 +2,7 @@ package hitbtc import ( "errors" + "fmt" "log" "sync" @@ -155,8 +156,19 @@ func (h *HitBTC) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]ex } // SubmitExchangeOrder submits a new order -func (h *HitBTC) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func (h *HitBTC) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + response, err := h.PlaceOrder(p.Pair().String(), price, amount, common.StringToLower(orderType.ToString()), common.StringToLower(side.ToString())) + + if response.OrderNumber > 0 { + submitOrderResponse.OrderID = fmt.Sprintf("%v", response.OrderNumber) + } + + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/huobi/huobi_test.go b/exchanges/huobi/huobi_test.go index c4bf97b7..18219937 100644 --- a/exchanges/huobi/huobi_test.go +++ b/exchanges/huobi/huobi_test.go @@ -5,6 +5,7 @@ import ( "crypto/rand" "crypto/x509" "encoding/pem" + "fmt" "io/ioutil" "strconv" "strings" @@ -12,14 +13,16 @@ import ( "github.com/thrasher-/gocryptotrader/common" "github.com/thrasher-/gocryptotrader/config" + "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" exchange "github.com/thrasher-/gocryptotrader/exchanges" ) // Please supply you own test keys here for due diligence testing. const ( - apiKey = "" - apiSecret = "" + apiKey = "" + apiSecret = "" + canPlaceOrders = false ) var h HUOBI @@ -201,7 +204,7 @@ func TestSpotNewOrder(t *testing.T) { arg := SpotNewOrderRequestParams{ Symbol: "btcusdt", - AccountID: 000000, + AccountID: 1, Amount: 0.01, Price: 10.1, Type: SpotNewOrderRequestTypeBuyLimit, @@ -393,3 +396,28 @@ func TestFormatWithdrawPermissions(t *testing.T) { t.Errorf("Expected: %s, Recieved: %s", expectedResult, withdrawPermissions) } } + +// This will really really use the API to place an order +// If you're going to test this, make sure you're willing to place real orders on the exchange +func TestSubmitOrder(t *testing.T) { + h.SetDefaults() + TestSetup(t) + h.Verbose = true + + if h.APIKey == "" || h.APISecret == "" || + h.APIKey == "Key" || h.APISecret == "Secret" || + !canPlaceOrders { + t.Skip(fmt.Sprintf("ApiKey: %s. Can place orders: %v", h.APIKey, canPlaceOrders)) + } + var p = pair.CurrencyPair{ + Delimiter: "", + FirstCurrency: symbol.BTC, + SecondCurrency: symbol.USDT, + } + accounts, err := h.GetAccounts() + + response, err := h.SubmitExchangeOrder(p, exchange.Buy, exchange.Limit, 1, 10, strconv.FormatInt(accounts[0].ID, 10)) + if err != nil || !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } +} diff --git a/exchanges/huobi/huobi_types.go b/exchanges/huobi/huobi_types.go index 7828cdb4..880f928c 100644 --- a/exchanges/huobi/huobi_types.go +++ b/exchanges/huobi/huobi_types.go @@ -196,12 +196,12 @@ type MarginAccountBalance struct { // SpotNewOrderRequestParams holds the params required to place // an order type SpotNewOrderRequestParams struct { - AccountID int `json:"account-id"` // Account ID, obtained using the accounts method. Curency trades use the accountid of the ‘spot’ account; for loan asset transactions, please use the accountid of the ‘margin’ account. - Amount float64 `json:"amount"` // The limit price indicates the quantity of the order, the market price indicates how much to buy when the order is paid, and the market price indicates how much the coin is sold when the order is sold. - Price float64 `json:"price"` // Order price, market price does not use this parameter - Source string `json:"source"` // Order source, api: API call, margin-api: loan asset transaction - Symbol string `json:"symbol"` // The symbol to use; example btcusdt, bccbtc...... - Type SpotNewOrderRequestParamsType `json:"type"` // 订单类型, buy-market: 市价买, sell-market: 市价卖, buy-limit: 限价买, sell-limit: 限价卖 + AccountID int `json:"account-id,string"` // Account ID, obtained using the accounts method. Curency trades use the accountid of the ‘spot’ account; for loan asset transactions, please use the accountid of the ‘margin’ account. + Amount float64 `json:"amount"` // The limit price indicates the quantity of the order, the market price indicates how much to buy when the order is paid, and the market price indicates how much the coin is sold when the order is sold. + Price float64 `json:"price"` // Order price, market price does not use this parameter + Source string `json:"source"` // Order source, api: API call, margin-api: loan asset transaction + Symbol string `json:"symbol"` // The symbol to use; example btcusdt, bccbtc...... + Type SpotNewOrderRequestParamsType `json:"type"` // 订单类型, buy-market: 市价买, sell-market: 市价卖, buy-limit: 限价买, sell-limit: 限价卖 } // SpotNewOrderRequestParamsType order type diff --git a/exchanges/huobi/huobi_wrapper.go b/exchanges/huobi/huobi_wrapper.go index 2187671f..0935faf4 100644 --- a/exchanges/huobi/huobi_wrapper.go +++ b/exchanges/huobi/huobi_wrapper.go @@ -2,7 +2,9 @@ package huobi import ( "errors" + "fmt" "log" + "strconv" "sync" "github.com/thrasher-/gocryptotrader/common" @@ -170,8 +172,44 @@ func (h *HUOBI) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]exc } // SubmitExchangeOrder submits a new order -func (h *HUOBI) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func (h *HUOBI) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + accountID, err := strconv.ParseInt(clientID, 10, 64) + var formattedType SpotNewOrderRequestParamsType + var params = SpotNewOrderRequestParams{ + Amount: amount, + Source: "api", + Symbol: common.StringToLower(p.Pair().String()), + AccountID: int(accountID), + } + + if side == exchange.Buy && orderType == exchange.Market { + formattedType = SpotNewOrderRequestTypeBuyMarket + } else if side == exchange.Sell && orderType == exchange.Market { + formattedType = SpotNewOrderRequestTypeSellMarket + } else if side == exchange.Buy && orderType == exchange.Limit { + formattedType = SpotNewOrderRequestTypeBuyLimit + params.Price = price + } else if side == exchange.Sell && orderType == exchange.Limit { + formattedType = SpotNewOrderRequestTypeSellLimit + params.Price = price + } else { + return submitOrderResponse, errors.New("Unsupported order type") + } + + params.Type = formattedType + + response, err := h.SpotNewOrder(params) + + if response > 0 { + submitOrderResponse.OrderID = fmt.Sprintf("%v", response) + } + + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/huobihadax/huobihadax_test.go b/exchanges/huobihadax/huobihadax_test.go index 07aeee61..07b4e593 100644 --- a/exchanges/huobihadax/huobihadax_test.go +++ b/exchanges/huobihadax/huobihadax_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/thrasher-/gocryptotrader/config" + "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" exchange "github.com/thrasher-/gocryptotrader/exchanges" ) @@ -13,8 +14,9 @@ import ( // Please supply your own APIKEYS here for due diligence testing const ( - apiKey = "" - apiSecret = "" + apiKey = "" + apiSecret = "" + canPlaceOrders = false ) var h HUOBIHADAX @@ -372,3 +374,28 @@ func TestFormatWithdrawPermissions(t *testing.T) { t.Errorf("Expected: %s, Recieved: %s", expectedResult, withdrawPermissions) } } + +// This will really really use the API to place an order +// If you're going to test this, make sure you're willing to place real orders on the exchange +func TestSubmitOrder(t *testing.T) { + h.SetDefaults() + TestSetup(t) + h.Verbose = true + + if h.APIKey == "" || h.APISecret == "" || + h.APIKey == "Key" || h.APISecret == "Secret" || + !canPlaceOrders { + t.Skip(fmt.Sprintf("ApiKey: %s. Can place orders: %v", h.APIKey, canPlaceOrders)) + } + var p = pair.CurrencyPair{ + Delimiter: "", + FirstCurrency: symbol.BTC, + SecondCurrency: symbol.USDT, + } + accounts, err := h.GetAccounts() + + response, err := h.SubmitExchangeOrder(p, exchange.Buy, exchange.Limit, 1, 10, strconv.FormatInt(accounts[0].ID, 10)) + if err != nil || !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } +} diff --git a/exchanges/huobihadax/huobihadax_wrapper.go b/exchanges/huobihadax/huobihadax_wrapper.go index a5c06baf..76626880 100644 --- a/exchanges/huobihadax/huobihadax_wrapper.go +++ b/exchanges/huobihadax/huobihadax_wrapper.go @@ -2,7 +2,9 @@ package huobihadax import ( "errors" + "fmt" "log" + "strconv" "sync" "github.com/thrasher-/gocryptotrader/common" @@ -135,8 +137,44 @@ func (h *HUOBIHADAX) GetExchangeHistory(p pair.CurrencyPair, assetType string) ( } // SubmitExchangeOrder submits a new order -func (h *HUOBIHADAX) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func (h *HUOBIHADAX) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + accountID, err := strconv.ParseInt(clientID, 0, 64) + var formattedType SpotNewOrderRequestParamsType + var params = SpotNewOrderRequestParams{ + Amount: amount, + Source: "api", + Symbol: common.StringToLower(p.Pair().String()), + AccountID: int(accountID), + } + + if side == exchange.Buy && orderType == exchange.Market { + formattedType = SpotNewOrderRequestTypeBuyMarket + } else if side == exchange.Sell && orderType == exchange.Market { + formattedType = SpotNewOrderRequestTypeSellMarket + } else if side == exchange.Buy && orderType == exchange.Limit { + formattedType = SpotNewOrderRequestTypeBuyLimit + params.Price = price + } else if side == exchange.Sell && orderType == exchange.Limit { + formattedType = SpotNewOrderRequestTypeSellLimit + params.Price = price + } else { + return submitOrderResponse, errors.New("Unsupported order type") + } + + params.Type = formattedType + + response, err := h.SpotNewOrder(params) + + if response > 0 { + submitOrderResponse.OrderID = fmt.Sprintf("%v", response) + } + + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/itbit/itbit_test.go b/exchanges/itbit/itbit_test.go index 013c75f8..31039aba 100644 --- a/exchanges/itbit/itbit_test.go +++ b/exchanges/itbit/itbit_test.go @@ -1,10 +1,12 @@ package itbit import ( + "fmt" "net/url" "testing" "github.com/thrasher-/gocryptotrader/config" + "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" exchange "github.com/thrasher-/gocryptotrader/exchanges" ) @@ -13,9 +15,10 @@ var i ItBit // Please provide your own keys to do proper testing const ( - apiKey = "" - apiSecret = "" - clientID = "" + apiKey = "" + apiSecret = "" + clientID = "" + canPlaceOrders = false ) func TestSetDefaults(t *testing.T) { @@ -241,3 +244,26 @@ func TestFormatWithdrawPermissions(t *testing.T) { t.Errorf("Expected: %s, Recieved: %s", expectedResult, withdrawPermissions) } } + +// This will really really use the API to place an order +// If you're going to test this, make sure you're willing to place real orders on the exchange +func TestSubmitOrder(t *testing.T) { + i.SetDefaults() + TestSetup(t) + i.Verbose = true + + if i.APIKey == "" || i.APISecret == "" || + i.APIKey == "Key" || i.APISecret == "Secret" || + !canPlaceOrders { + t.Skip(fmt.Sprintf("ApiKey: %s. Can place orders: %v", i.APIKey, canPlaceOrders)) + } + var p = pair.CurrencyPair{ + Delimiter: "", + FirstCurrency: symbol.BTC, + SecondCurrency: symbol.USDT, + } + response, err := i.SubmitExchangeOrder(p, exchange.Buy, exchange.Limit, 1, 10, "hi") + if err != nil || !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } +} diff --git a/exchanges/itbit/itbit_wrapper.go b/exchanges/itbit/itbit_wrapper.go index f7703d30..ab06e7a1 100644 --- a/exchanges/itbit/itbit_wrapper.go +++ b/exchanges/itbit/itbit_wrapper.go @@ -2,6 +2,7 @@ package itbit import ( "errors" + "fmt" "log" "strconv" "sync" @@ -129,8 +130,39 @@ func (i *ItBit) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]exc } // SubmitExchangeOrder submits a new order -func (i *ItBit) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func (i *ItBit) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + var wallet string + + wallets, err := i.GetWallets(nil) + if err != nil { + return submitOrderResponse, err + } + + // Determine what wallet ID to use if there is any actual available currency to make the trade! + for _, i := range wallets { + for j := range i.Balances { + if i.Balances[j].Currency == p.FirstCurrency.String() && i.Balances[j].AvailableBalance >= amount { + wallet = i.ID + } + } + } + + if wallet == "" { + return submitOrderResponse, fmt.Errorf("No wallet found with currency: %s with amount >= %v", p.FirstCurrency.String(), amount) + } + + response, err := i.PlaceOrder(wallet, side.ToString(), orderType.ToString(), p.FirstCurrency.String(), amount, price, p.Pair().String(), "") + + if response.ID != "" { + submitOrderResponse.OrderID = response.ID + } + + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/kraken/kraken.go b/exchanges/kraken/kraken.go index 501393ea..f220a5bf 100644 --- a/exchanges/kraken/kraken.go +++ b/exchanges/kraken/kraken.go @@ -788,12 +788,12 @@ func (k *Kraken) GetTradeVolume(feeinfo bool, symbol ...string) (TradeVolumeResp 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}, + "type": {common.StringToLower(side)}, + "ordertype": {common.StringToLower(orderType)}, "volume": {strconv.FormatFloat(volume, 'f', -1, 64)}, } - if price != 0 { + if orderType == "limit" || price > 0 { params.Set("price", strconv.FormatFloat(price, 'f', -1, 64)) } diff --git a/exchanges/kraken/kraken_test.go b/exchanges/kraken/kraken_test.go index 89990610..18736fad 100644 --- a/exchanges/kraken/kraken_test.go +++ b/exchanges/kraken/kraken_test.go @@ -1,9 +1,11 @@ package kraken import ( + "fmt" "testing" "github.com/thrasher-/gocryptotrader/config" + "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" exchange "github.com/thrasher-/gocryptotrader/exchanges" ) @@ -12,9 +14,10 @@ var k Kraken // Please add your own APIkeys to do correct due diligence testing. const ( - apiKey = "" - apiSecret = "" - clientID = "" + apiKey = "" + apiSecret = "" + clientID = "" + canPlaceOrders = false ) func TestSetDefaults(t *testing.T) { @@ -327,3 +330,26 @@ func TestFormatWithdrawPermissions(t *testing.T) { t.Errorf("Expected: %s, Recieved: %s", expectedResult, withdrawPermissions) } } + +// This will really really use the API to place an order +// If you're going to test this, make sure you're willing to place real orders on the exchange +func TestSubmitOrder(t *testing.T) { + k.SetDefaults() + TestSetup(t) + k.Verbose = true + + if k.APIKey == "" || k.APISecret == "" || + k.APIKey == "Key" || k.APISecret == "Secret" || + !canPlaceOrders { + t.Skip(fmt.Sprintf("ApiKey: %s. Can place orders: %v", k.APIKey, canPlaceOrders)) + } + var p = pair.CurrencyPair{ + Delimiter: "", + FirstCurrency: symbol.XBT, + SecondCurrency: symbol.CAD, + } + response, err := k.SubmitExchangeOrder(p, exchange.Buy, exchange.Market, 1, 10, "hi") + if err != nil || !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } +} diff --git a/exchanges/kraken/kraken_wrapper.go b/exchanges/kraken/kraken_wrapper.go index b2ff9e01..e97b13a3 100644 --- a/exchanges/kraken/kraken_wrapper.go +++ b/exchanges/kraken/kraken_wrapper.go @@ -3,6 +3,7 @@ package kraken import ( "errors" "log" + "strings" "sync" "github.com/thrasher-/gocryptotrader/common" @@ -161,8 +162,21 @@ func (k *Kraken) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]ex } // SubmitExchangeOrder submits a new order -func (k *Kraken) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func (k *Kraken) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + var args = AddOrderOptions{} + + response, err := k.AddOrder(p.Pair().String(), side.ToString(), orderType.ToString(), amount, price, 0, 0, args) + + if len(response.TransactionIds) > 0 { + submitOrderResponse.OrderID = strings.Join(response.TransactionIds, ", ") + } + + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/lakebtc/lakebtc.go b/exchanges/lakebtc/lakebtc.go index ed402b88..3088a02d 100644 --- a/exchanges/lakebtc/lakebtc.go +++ b/exchanges/lakebtc/lakebtc.go @@ -219,11 +219,11 @@ func (l *LakeBTC) GetAccountInfo() (AccountInfo, error) { // Trade executes an order on the exchange and returns trade inforamtion or an // error -func (l *LakeBTC) Trade(orderType int, amount, price float64, currency string) (Trade, error) { +func (l *LakeBTC) Trade(isBuyOrder bool, amount, price float64, currency string) (Trade, error) { resp := Trade{} params := strconv.FormatFloat(price, 'f', -1, 64) + "," + strconv.FormatFloat(amount, 'f', -1, 64) + "," + currency - if orderType == 1 { + if isBuyOrder { if err := l.SendAuthenticatedHTTPRequest(lakeBTCBuyOrder, params, &resp); err != nil { return resp, err } diff --git a/exchanges/lakebtc/lakebtc_test.go b/exchanges/lakebtc/lakebtc_test.go index ef35b44a..4b069d51 100644 --- a/exchanges/lakebtc/lakebtc_test.go +++ b/exchanges/lakebtc/lakebtc_test.go @@ -1,9 +1,11 @@ package lakebtc import ( + "fmt" "testing" "github.com/thrasher-/gocryptotrader/config" + "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" exchange "github.com/thrasher-/gocryptotrader/exchanges" ) @@ -12,8 +14,9 @@ var l LakeBTC // Please add your own APIkeys to do correct due diligence testing. const ( - apiKey = "" - apiSecret = "" + apiKey = "" + apiSecret = "" + canPlaceOrders = false ) func TestSetDefaults(t *testing.T) { @@ -72,7 +75,7 @@ func TestTrade(t *testing.T) { if l.APIKey == "" || l.APISecret == "" { t.Skip() } - _, err := l.Trade(0, 0, 0, "USD") + _, err := l.Trade(false, 0, 0, "USD") if err == nil { t.Error("Test Failed - Trade() error", err) } @@ -245,3 +248,26 @@ func TestFormatWithdrawPermissions(t *testing.T) { t.Errorf("Expected: %s, Recieved: %s", expectedResult, withdrawPermissions) } } + +// This will really really use the API to place an order +// If you're going to test this, make sure you're willing to place real orders on the exchange +func TestSubmitOrder(t *testing.T) { + l.SetDefaults() + TestSetup(t) + l.Verbose = true + + if l.APIKey == "" || l.APISecret == "" || + l.APIKey == "Key" || l.APISecret == "Secret" || + !canPlaceOrders { + t.Skip(fmt.Sprintf("ApiKey: %s. Can place orders: %v", l.APIKey, canPlaceOrders)) + } + var p = pair.CurrencyPair{ + Delimiter: "", + FirstCurrency: symbol.BTC, + SecondCurrency: symbol.EUR, + } + response, err := l.SubmitExchangeOrder(p, exchange.Buy, exchange.Market, 1, 10, "hi") + if err != nil || !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } +} diff --git a/exchanges/lakebtc/lakebtc_wrapper.go b/exchanges/lakebtc/lakebtc_wrapper.go index ace3b044..e64176f0 100644 --- a/exchanges/lakebtc/lakebtc_wrapper.go +++ b/exchanges/lakebtc/lakebtc_wrapper.go @@ -2,6 +2,7 @@ package lakebtc import ( "errors" + "fmt" "log" "strconv" "sync" @@ -139,8 +140,20 @@ func (l *LakeBTC) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]e } // SubmitExchangeOrder submits a new order -func (l *LakeBTC) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func (l *LakeBTC) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + isBuyOrder := side == exchange.Buy + response, err := l.Trade(isBuyOrder, amount, price, common.StringToLower(p.Pair().String())) + + if response.ID > 0 { + submitOrderResponse.OrderID = fmt.Sprintf("%v", response.ID) + } + + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/liqui/liqui_test.go b/exchanges/liqui/liqui_test.go index bb3cb9c6..6819150c 100644 --- a/exchanges/liqui/liqui_test.go +++ b/exchanges/liqui/liqui_test.go @@ -1,6 +1,7 @@ package liqui import ( + "fmt" "net/url" "testing" @@ -13,8 +14,9 @@ import ( var l Liqui const ( - apiKey = "" - apiSecret = "" + apiKey = "" + apiSecret = "" + canPlaceOrders = false ) func TestSetDefaults(t *testing.T) { @@ -231,3 +233,26 @@ func TestFormatWithdrawPermissions(t *testing.T) { t.Errorf("Expected: %s, Recieved: %s", expectedResult, withdrawPermissions) } } + +// This will really really use the API to place an order +// If you're going to test this, make sure you're willing to place real orders on the exchange +func TestSubmitOrder(t *testing.T) { + l.SetDefaults() + TestSetup(t) + l.Verbose = true + + if l.APIKey == "" || l.APISecret == "" || + l.APIKey == "Key" || l.APISecret == "Secret" || + !canPlaceOrders { + t.Skip(fmt.Sprintf("ApiKey: %s. Can place orders: %v", l.APIKey, canPlaceOrders)) + } + var p = pair.CurrencyPair{ + Delimiter: "", + FirstCurrency: symbol.BTC, + SecondCurrency: symbol.EUR, + } + response, err := l.SubmitExchangeOrder(p, exchange.Buy, exchange.Market, 1, 10, "hi") + if err != nil || !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } +} diff --git a/exchanges/liqui/liqui_wrapper.go b/exchanges/liqui/liqui_wrapper.go index 77a5705e..9c4447d7 100644 --- a/exchanges/liqui/liqui_wrapper.go +++ b/exchanges/liqui/liqui_wrapper.go @@ -2,6 +2,7 @@ package liqui import ( "errors" + "fmt" "log" "sync" @@ -148,8 +149,19 @@ func (l *Liqui) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]exc } // SubmitExchangeOrder submits a new order -func (l *Liqui) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func (l *Liqui) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + response, err := l.Trade(p.Pair().String(), fmt.Sprintf("%s", orderType), amount, price) + + if response > 0 { + submitOrderResponse.OrderID = fmt.Sprintf("%v", response) + } + + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/localbitcoins/localbitcoins_wrapper.go b/exchanges/localbitcoins/localbitcoins_wrapper.go index 5612b2ed..f175b3d5 100644 --- a/exchanges/localbitcoins/localbitcoins_wrapper.go +++ b/exchanges/localbitcoins/localbitcoins_wrapper.go @@ -2,7 +2,9 @@ package localbitcoins import ( "errors" + "fmt" "log" + "math" "sync" "github.com/thrasher-/gocryptotrader/currency/pair" @@ -120,8 +122,70 @@ func (l *LocalBitcoins) GetExchangeHistory(p pair.CurrencyPair, assetType string } // SubmitExchangeOrder submits a new order -func (l *LocalBitcoins) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func (l *LocalBitcoins) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + // These are placeholder details + // TODO store a user's localbitcoin details to use here + var params = AdCreate{ + PriceEquation: "USD_in_AUD", + Latitude: 1, + Longitude: 1, + City: "City", + Location: "Location", + CountryCode: "US", + Currency: p.SecondCurrency.String(), + AccountInfo: "-", + BankName: "Bank", + MSG: fmt.Sprintf("%s", side.ToString()), + SMSVerficationRequired: true, + TrackMaxAmount: true, + RequireTrustedByAdvertiser: true, + RequireIdentification: true, + OnlineProvider: "", + TradeType: "", + MinAmount: int(math.Round(amount)), + } + + // Does not return any orderID, so create the add, then get the order + err := l.CreateAd(params) + if err != nil { + return submitOrderResponse, err + } + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + // Now to figure out what ad we just submitted + // The only details we have are the params above + var adID string + ads, err := l.Getads() + for _, i := range ads.AdList { + if i.Data.PriceEquation == params.PriceEquation && + i.Data.Lat == float64(params.Latitude) && + i.Data.Lon == float64(params.Longitude) && + i.Data.City == params.City && + i.Data.Location == params.Location && + i.Data.CountryCode == params.CountryCode && + i.Data.Currency == params.Currency && + i.Data.AccountInfo == params.AccountInfo && + i.Data.BankName == params.BankName && + i.Data.SMSVerficationRequired == params.SMSVerficationRequired && + i.Data.TrackMaxAmount == params.TrackMaxAmount && + i.Data.RequireTrustedByAdvertiser == params.RequireTrustedByAdvertiser && + i.Data.OnlineProvider == params.OnlineProvider && + i.Data.TradeType == params.TradeType && + i.Data.MinAmount == fmt.Sprintf("%v", params.MinAmount) { + adID = fmt.Sprintf("%v", i.Data.AdID) + } + } + + if adID != "" { + submitOrderResponse.OrderID = adID + } else { + return submitOrderResponse, errors.New("Ad placed, but not found via API") + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/okcoin/okcoin_test.go b/exchanges/okcoin/okcoin_test.go index cabd8b25..af23284c 100644 --- a/exchanges/okcoin/okcoin_test.go +++ b/exchanges/okcoin/okcoin_test.go @@ -1,9 +1,11 @@ package okcoin import ( + "fmt" "testing" "github.com/thrasher-/gocryptotrader/config" + "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" exchange "github.com/thrasher-/gocryptotrader/exchanges" ) @@ -13,8 +15,9 @@ var o OKCoin // Please supply your own APIKEYS here for due diligence testing const ( - apiKey = "" - apiSecret = "" + apiKey = "" + apiSecret = "" + canPlaceOrders = false ) func TestSetDefaults(t *testing.T) { @@ -137,3 +140,26 @@ func TestFormatWithdrawPermissions(t *testing.T) { t.Errorf("Expected: %s, Recieved: %s", expectedResult, withdrawPermissions) } } + +// This will really really use the API to place an order +// If you're going to test this, make sure you're willing to place real orders on the exchange +func TestSubmitOrder(t *testing.T) { + o.SetDefaults() + TestSetup(t) + o.Verbose = true + + if o.APIKey == "" || o.APISecret == "" || + o.APIKey == "Key" || o.APISecret == "Secret" || + !canPlaceOrders { + t.Skip(fmt.Sprintf("ApiKey: %s. Can place orders: %v", o.APIKey, canPlaceOrders)) + } + var p = pair.CurrencyPair{ + Delimiter: "", + FirstCurrency: symbol.BTC, + SecondCurrency: symbol.EUR, + } + response, err := o.SubmitExchangeOrder(p, exchange.Buy, exchange.Market, 1, 10, "hi") + if err != nil || !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } +} diff --git a/exchanges/okcoin/okcoin_wrapper.go b/exchanges/okcoin/okcoin_wrapper.go index 2ecbe16c..75778c96 100644 --- a/exchanges/okcoin/okcoin_wrapper.go +++ b/exchanges/okcoin/okcoin_wrapper.go @@ -2,6 +2,7 @@ package okcoin import ( "errors" + "fmt" "log" "sync" @@ -186,8 +187,36 @@ func (o *OKCoin) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]ex } // SubmitExchangeOrder submits a new order -func (o *OKCoin) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func (o *OKCoin) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + var oT string + if orderType == exchange.Limit { + if side == exchange.Buy { + oT = "buy" + } else { + oT = "sell" + } + } else if orderType == exchange.Market { + if side == exchange.Buy { + oT = "buy_market" + } else { + oT = "sell_market" + } + } else { + return submitOrderResponse, errors.New("Unsupported order type") + } + + response, err := o.Trade(amount, price, p.Pair().String(), oT) + + if response > 0 { + submitOrderResponse.OrderID = fmt.Sprintf("%v", response) + } + + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/okex/okex_test.go b/exchanges/okex/okex_test.go index 4884bfe5..9e3147aa 100644 --- a/exchanges/okex/okex_test.go +++ b/exchanges/okex/okex_test.go @@ -1,9 +1,11 @@ package okex import ( + "fmt" "testing" "github.com/thrasher-/gocryptotrader/config" + "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" exchange "github.com/thrasher-/gocryptotrader/exchanges" ) @@ -12,8 +14,9 @@ var o OKEX // Please supply you own test keys here for due diligence testing. const ( - apiKey = "" - apiSecret = "" + apiKey = "" + apiSecret = "" + canPlaceOrders = false ) func TestSetDefaults(t *testing.T) { @@ -386,3 +389,26 @@ func TestFormatWithdrawPermissions(t *testing.T) { t.Errorf("Expected: %s, Recieved: %s", expectedResult, withdrawPermissions) } } + +// This will really really use the API to place an order +// If you're going to test this, make sure you're willing to place real orders on the exchange +func TestSubmitOrder(t *testing.T) { + o.SetDefaults() + TestSetup(t) + o.Verbose = true + + if o.APIKey == "" || o.APISecret == "" || + o.APIKey == "Key" || o.APISecret == "Secret" || + !canPlaceOrders { + t.Skip(fmt.Sprintf("ApiKey: %s. Can place orders: %v", o.APIKey, canPlaceOrders)) + } + var p = pair.CurrencyPair{ + Delimiter: "", + FirstCurrency: symbol.BTC, + SecondCurrency: symbol.EUR, + } + response, err := o.SubmitExchangeOrder(p, exchange.Buy, exchange.Market, 1, 10, "hi") + if err != nil || !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } +} diff --git a/exchanges/okex/okex_wrapper.go b/exchanges/okex/okex_wrapper.go index 792e21ea..63a243b2 100644 --- a/exchanges/okex/okex_wrapper.go +++ b/exchanges/okex/okex_wrapper.go @@ -2,6 +2,7 @@ package okex import ( "errors" + "fmt" "log" "sync" @@ -152,8 +153,44 @@ func (o *OKEX) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]exch } // SubmitExchangeOrder submits a new order -func (o *OKEX) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func (o *OKEX) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + var oT SpotNewOrderRequestType + + if orderType == exchange.Limit { + if side == exchange.Buy { + oT = SpotNewOrderRequestTypeBuy + } else { + oT = SpotNewOrderRequestTypeSell + } + } else if orderType == exchange.Market { + if side == exchange.Buy { + oT = SpotNewOrderRequestTypeBuyMarket + } else { + oT = SpotNewOrderRequestTypeSellMarket + } + } else { + return submitOrderResponse, errors.New("Unsupported order type") + } + + var params = SpotNewOrderRequestParams{ + Amount: amount, + Price: price, + Symbol: p.Pair().String(), + Type: oT, + } + + response, err := o.SpotNewOrder(params) + + if response > 0 { + submitOrderResponse.OrderID = fmt.Sprintf("%v", response) + } + + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/poloniex/poloniex_test.go b/exchanges/poloniex/poloniex_test.go index abcdf121..7ba754fa 100644 --- a/exchanges/poloniex/poloniex_test.go +++ b/exchanges/poloniex/poloniex_test.go @@ -1,9 +1,11 @@ package poloniex import ( + "fmt" "testing" "github.com/thrasher-/gocryptotrader/config" + "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" exchange "github.com/thrasher-/gocryptotrader/exchanges" ) @@ -13,8 +15,9 @@ var p Poloniex // Please supply your own APIKEYS here for due diligence testing const ( - apiKey = "" - apiSecret = "" + apiKey = "" + apiSecret = "" + canPlaceOrders = false ) func TestSetDefaults(t *testing.T) { @@ -190,3 +193,26 @@ func TestFormatWithdrawPermissions(t *testing.T) { t.Errorf("Expected: %s, Recieved: %s", expectedResult, withdrawPermissions) } } + +// This will really really use the API to place an order +// If you're going to test this, make sure you're willing to place real orders on the exchange +func TestSubmitOrder(t *testing.T) { + p.SetDefaults() + TestSetup(t) + p.Verbose = true + + if p.APIKey == "" || p.APISecret == "" || + p.APIKey == "Key" || p.APISecret == "Secret" || + !canPlaceOrders { + t.Skip(fmt.Sprintf("ApiKey: %s. Can place orders: %v", p.APIKey, canPlaceOrders)) + } + var pair = pair.CurrencyPair{ + Delimiter: "_", + FirstCurrency: symbol.BTC, + SecondCurrency: symbol.LTC, + } + response, err := p.SubmitExchangeOrder(pair, exchange.Buy, exchange.Market, 1, 10, "hi") + if err != nil || !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } +} diff --git a/exchanges/poloniex/poloniex_wrapper.go b/exchanges/poloniex/poloniex_wrapper.go index ea4a5d64..c88ce245 100644 --- a/exchanges/poloniex/poloniex_wrapper.go +++ b/exchanges/poloniex/poloniex_wrapper.go @@ -2,6 +2,7 @@ package poloniex import ( "errors" + "fmt" "log" "sync" @@ -155,8 +156,21 @@ func (p *Poloniex) GetExchangeHistory(currencyPair pair.CurrencyPair, assetType } // SubmitExchangeOrder submits a new order -func (p *Poloniex) SubmitExchangeOrder(currencyPair pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func (p *Poloniex) SubmitExchangeOrder(currencyPair pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + fillOrKill := orderType == exchange.Market + isBuyOrder := side == exchange.Buy + response, err := p.PlaceOrder(currencyPair.Pair().String(), price, amount, false, fillOrKill, isBuyOrder) + + if response.OrderNumber > 0 { + submitOrderResponse.OrderID = fmt.Sprintf("%v", response.OrderNumber) + } + + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/wex/wex_test.go b/exchanges/wex/wex_test.go index 33c7052a..61aeb0c5 100644 --- a/exchanges/wex/wex_test.go +++ b/exchanges/wex/wex_test.go @@ -1,9 +1,11 @@ package wex import ( + "fmt" "testing" "github.com/thrasher-/gocryptotrader/config" + "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" exchange "github.com/thrasher-/gocryptotrader/exchanges" ) @@ -12,8 +14,9 @@ var w WEX // Please supply your own keys for better unit testing const ( - apiKey = "" - apiSecret = "" + apiKey = "" + apiSecret = "" + canPlaceOrders = false ) func TestSetDefaults(t *testing.T) { @@ -265,3 +268,26 @@ func TestFormatWithdrawPermissions(t *testing.T) { t.Errorf("Expected: %s, Recieved: %s", expectedResult, withdrawPermissions) } } + +// This will really really use the API to place an order +// If you're going to test this, make sure you're willing to place real orders on the exchange +func TestSubmitOrder(t *testing.T) { + w.SetDefaults() + TestSetup(t) + w.Verbose = true + + if w.APIKey == "" || w.APISecret == "" || + w.APIKey == "Key" || w.APISecret == "Secret" || + !canPlaceOrders { + t.Skip(fmt.Sprintf("ApiKey: %s. Can place orders: %v", w.APIKey, canPlaceOrders)) + } + var pair = pair.CurrencyPair{ + Delimiter: "_", + FirstCurrency: symbol.BTC, + SecondCurrency: symbol.USD, + } + response, err := w.SubmitExchangeOrder(pair, exchange.Buy, exchange.Market, 1, 10, "hi") + if err != nil || !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } +} diff --git a/exchanges/wex/wex_wrapper.go b/exchanges/wex/wex_wrapper.go index 79ead6ea..0b365414 100644 --- a/exchanges/wex/wex_wrapper.go +++ b/exchanges/wex/wex_wrapper.go @@ -2,6 +2,7 @@ package wex import ( "errors" + "fmt" "log" "sync" @@ -158,8 +159,19 @@ func (w *WEX) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]excha } // SubmitExchangeOrder submits a new order -func (w *WEX) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func (w *WEX) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + response, err := w.Trade(common.StringToLower(p.Pair().String()), common.StringToLower(side.ToString()), amount, price) + + if response > 0 { + submitOrderResponse.OrderID = fmt.Sprintf("%v", response) + } + + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/yobit/yobit_test.go b/exchanges/yobit/yobit_test.go index 0335d995..8ecf21d3 100644 --- a/exchanges/yobit/yobit_test.go +++ b/exchanges/yobit/yobit_test.go @@ -1,9 +1,11 @@ package yobit import ( + "fmt" "testing" "github.com/thrasher-/gocryptotrader/config" + "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" exchange "github.com/thrasher-/gocryptotrader/exchanges" ) @@ -12,8 +14,9 @@ var y Yobit // Please supply your own keys for better unit testing const ( - apiKey = "" - apiSecret = "" + apiKey = "" + apiSecret = "" + canPlaceOrders = false ) func TestSetDefaults(t *testing.T) { @@ -309,3 +312,26 @@ func TestFormatWithdrawPermissions(t *testing.T) { t.Errorf("Expected: %s, Recieved: %s", expectedResult, withdrawPermissions) } } + +// This will really really use the API to place an order +// If you're going to test this, make sure you're willing to place real orders on the exchange +func TestSubmitOrder(t *testing.T) { + y.SetDefaults() + TestSetup(t) + y.Verbose = true + + if y.APIKey == "" || y.APISecret == "" || + y.APIKey == "Key" || y.APISecret == "Secret" || + !canPlaceOrders { + t.Skip(fmt.Sprintf("ApiKey: %s. Can place orders: %v", y.APIKey, canPlaceOrders)) + } + var pair = pair.CurrencyPair{ + Delimiter: "_", + FirstCurrency: symbol.BTC, + SecondCurrency: symbol.USD, + } + response, err := y.SubmitExchangeOrder(pair, exchange.Buy, exchange.Market, 1, 10, "hi") + if err != nil || !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } +} diff --git a/exchanges/yobit/yobit_wrapper.go b/exchanges/yobit/yobit_wrapper.go index 7a74fab7..46e14bbe 100644 --- a/exchanges/yobit/yobit_wrapper.go +++ b/exchanges/yobit/yobit_wrapper.go @@ -2,6 +2,7 @@ package yobit import ( "errors" + "fmt" "log" "sync" @@ -140,8 +141,19 @@ func (y *Yobit) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]exc } // SubmitExchangeOrder submits a new order -func (y *Yobit) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func (y *Yobit) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + response, err := y.Trade(p.Pair().String(), orderType.ToString(), amount, price) + + if response > 0 { + submitOrderResponse.OrderID = fmt.Sprintf("%v", response) + } + + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/exchanges/zb/zb_test.go b/exchanges/zb/zb_test.go index 77da1e28..7d2e8eb6 100644 --- a/exchanges/zb/zb_test.go +++ b/exchanges/zb/zb_test.go @@ -5,14 +5,16 @@ import ( "testing" "github.com/thrasher-/gocryptotrader/config" + "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" exchange "github.com/thrasher-/gocryptotrader/exchanges" ) // Please supply you own test keys here for due diligence testing. const ( - apiKey = "" - apiSecret = "" + apiKey = "" + apiSecret = "" + canPlaceOrders = false ) var z ZB @@ -240,3 +242,26 @@ func TestFormatWithdrawPermissions(t *testing.T) { t.Errorf("Expected: %s, Recieved: %s", expectedResult, withdrawPermissions) } } + +// This will really really use the API to place an order +// If you're going to test this, make sure you're willing to place real orders on the exchange +func TestSubmitOrder(t *testing.T) { + z.SetDefaults() + TestSetup(t) + z.Verbose = true + + if z.APIKey == "" || z.APISecret == "" || + z.APIKey == "Key" || z.APISecret == "Secret" || + !canPlaceOrders { + t.Skip(fmt.Sprintf("ApiKey: %s. Can place orders: %v", z.APIKey, canPlaceOrders)) + } + var pair = pair.CurrencyPair{ + Delimiter: "_", + FirstCurrency: symbol.QTUM, + SecondCurrency: symbol.USDT, + } + response, err := z.SubmitExchangeOrder(pair, exchange.Buy, exchange.Market, 1, 10, "hi") + if err != nil || !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } +} diff --git a/exchanges/zb/zb_wrapper.go b/exchanges/zb/zb_wrapper.go index f99d68fc..d3fc2007 100644 --- a/exchanges/zb/zb_wrapper.go +++ b/exchanges/zb/zb_wrapper.go @@ -2,6 +2,7 @@ package zb import ( "errors" + "fmt" "log" "sync" @@ -136,8 +137,33 @@ func (z *ZB) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]exchan } // SubmitExchangeOrder submits a new order -func (z *ZB) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func (z *ZB) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + var submitOrderResponse exchange.SubmitOrderResponse + var oT SpotNewOrderRequestParamsType + + if side == exchange.Buy { + oT = SpotNewOrderRequestParamsTypeBuy + } else { + oT = SpotNewOrderRequestParamsTypeSell + } + + var params = SpotNewOrderRequestParams{ + Amount: amount, + Price: price, + Symbol: common.StringToLower(p.Pair().String()), + Type: oT, + } + response, err := z.SpotNewOrder(params) + + if response > 0 { + submitOrderResponse.OrderID = fmt.Sprintf("%v", response) + } + + if err == nil { + submitOrderResponse.IsOrderPlaced = true + } + + return submitOrderResponse, err } // ModifyExchangeOrder will allow of changing orderbook placement and limit to diff --git a/tools/exchange_template/wrapper_file.tmpl b/tools/exchange_template/wrapper_file.tmpl index ce5f5a88..07b2620e 100644 --- a/tools/exchange_template/wrapper_file.tmpl +++ b/tools/exchange_template/wrapper_file.tmpl @@ -121,8 +121,8 @@ func ({{.Variable}} *{{.CapitalName}}) GetExchangeHistory(p pair.CurrencyPair, a } // SubmitExchangeOrder submits a new order -func ({{.Variable}} *{{.CapitalName}}) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (int64, error) { - return 0, errors.New("not yet implemented") +func ({{.Variable}} *{{.CapitalName}}) SubmitExchangeOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { + return "", errors.New("not yet implemented") } // ModifyExchangeOrder will allow of changing orderbook placement and limit to