Skip to content

Commit

Permalink
btcmarkets: update order submission (thrasher-corp#908)
Browse files Browse the repository at this point in the history
* btcm/order: update order submission

* btcmarkets: addr nits

* btcmarkets: reinstate new order test
  • Loading branch information
shazbert authored Mar 25, 2022
1 parent 489e2eb commit 022001f
Show file tree
Hide file tree
Showing 12 changed files with 321 additions and 97 deletions.
5 changes: 3 additions & 2 deletions engine/order_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -572,13 +572,14 @@ func (m *OrderManager) processSubmittedOrder(newOrder *order.Submit, result orde
if newOrder.Date.IsZero() {
newOrder.Date = time.Now()
}
msg := fmt.Sprintf("Order manager: Exchange %s submitted order ID=%v [Ours: %v] pair=%v price=%v amount=%v side=%v type=%v for time %v.",
msg := fmt.Sprintf("Order manager: Exchange %s submitted order ID=%v [Ours: %v] pair=%v price=%v amount=%v quoteAmount=%v side=%v type=%v for time %v.",
newOrder.Exchange,
result.OrderID,
id.String(),
newOrder.Pair,
newOrder.Price,
newOrder.Amount,
newOrder.QuoteAmount,
newOrder.Side,
newOrder.Type,
newOrder.Date)
Expand All @@ -602,7 +603,7 @@ func (m *OrderManager) processSubmittedOrder(newOrder *order.Submit, result orde
LimitPriceUpper: newOrder.LimitPriceUpper,
LimitPriceLower: newOrder.LimitPriceLower,
TriggerPrice: newOrder.TriggerPrice,
TargetAmount: newOrder.TargetAmount,
QuoteAmount: newOrder.QuoteAmount,
ExecutedAmount: newOrder.ExecutedAmount,
RemainingAmount: newOrder.RemainingAmount,
Fee: newOrder.Fee,
Expand Down
2 changes: 1 addition & 1 deletion exchanges/binance/binance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2610,7 +2610,7 @@ func TestWsOrderExecutionReport(t *testing.T) {
Price: 52789.1,
Amount: 0.00028400,
AverageExecutedPrice: 0,
TargetAmount: 0,
QuoteAmount: 0,
ExecutedAmount: 0,
RemainingAmount: 0.00028400,
Cost: 0,
Expand Down
70 changes: 64 additions & 6 deletions exchanges/btcmarkets/btcmarkets.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/url"
Expand All @@ -16,6 +17,7 @@ import (
"github.com/thrasher-corp/gocryptotrader/common/crypto"
"github.com/thrasher-corp/gocryptotrader/currency"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
)

Expand Down Expand Up @@ -57,13 +59,23 @@ const (
orderPlaced = "Placed"
orderAccepted = "Accepted"

ask = "ask"
ask = "ask"

// order types
limit = "Limit"
market = "Market"
stopLimit = "Stop Limit"
stop = "Stop"
takeProfit = "Take Profit"

// order sides
askSide = "Ask"
bidSide = "Bid"

// time in force
immediateOrCancel = "IOC"
fillOrKill = "FOK"

subscribe = "subscribe"
fundChange = "fundChange"
orderChange = "orderChange"
Expand Down Expand Up @@ -314,13 +326,56 @@ func (b *BTCMarkets) GetTradeByID(ctx context.Context, id string) (TradeHistoryD
request.Auth)
}

// formatOrderType conforms order type to the exchange acceptable order type
// strings
func (b *BTCMarkets) formatOrderType(o order.Type) (string, error) {
switch o {
case order.Limit:
return limit, nil
case order.Market:
return market, nil
case order.StopLimit:
return stopLimit, nil
case order.Stop:
return stop, nil
case order.TakeProfit:
return takeProfit, nil
default:
return "", fmt.Errorf("%s %s %w", b.Name, o, order.ErrTypeIsInvalid)
}
}

// formatOrderSide conforms order side to the exchange acceptable order side
// strings
func (b *BTCMarkets) formatOrderSide(o order.Side) (string, error) {
switch o {
case order.Ask:
return askSide, nil
case order.Bid:
return bidSide, nil
default:
return "", fmt.Errorf("%s %s %w", b.Name, o, order.ErrSideIsInvalid)
}
}

// getTimeInForce returns a string depending on the options in order.Submit
func (b *BTCMarkets) getTimeInForce(s *order.Submit) string {
if s.ImmediateOrCancel {
return immediateOrCancel
}
if s.FillOrKill {
return fillOrKill
}
return "" // GTC (good till cancelled, default value)
}

// NewOrder requests a new order and returns an ID
func (b *BTCMarkets) NewOrder(ctx context.Context, marketID string, price, amount float64, orderType, side string, triggerPrice,
targetAmount float64, timeInForce string, postOnly bool, selfTrade, clientOrderID string) (OrderData, error) {
var resp OrderData
func (b *BTCMarkets) NewOrder(ctx context.Context, price, amount, triggerPrice, targetAmount float64, marketID, orderType, side, timeInForce, selfTrade, clientOrderID string, postOnly bool) (OrderData, error) {
req := make(map[string]interface{})
req["marketId"] = marketID
req["price"] = strconv.FormatFloat(price, 'f', -1, 64)
if price != 0 {
req["price"] = strconv.FormatFloat(price, 'f', -1, 64)
}
req["amount"] = strconv.FormatFloat(amount, 'f', -1, 64)
req["type"] = orderType
req["side"] = side
Expand All @@ -333,13 +388,16 @@ func (b *BTCMarkets) NewOrder(ctx context.Context, marketID string, price, amoun
if timeInForce != "" {
req["timeInForce"] = timeInForce
}
req["postOnly"] = postOnly
if postOnly {
req["postOnly"] = postOnly
}
if selfTrade != "" {
req["selfTrade"] = selfTrade
}
if clientOrderID != "" {
req["clientOrderID"] = clientOrderID
}
var resp OrderData
return resp, b.SendAuthenticatedRequest(ctx, http.MethodPost,
btcMarketsOrders,
req,
Expand Down
151 changes: 140 additions & 11 deletions exchanges/btcmarkets/btcmarkets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,25 +202,57 @@ func TestGetTradeByID(t *testing.T) {
}
}

func TestNewOrder(t *testing.T) {
func TestSubmitOrder(t *testing.T) {
t.Parallel()
_, err := b.SubmitOrder(context.Background(), &order.Submit{
Price: 100,
Amount: 1,
Type: order.TrailingStop,
AssetType: asset.Spot,
Side: order.Bid,
Pair: currency.NewPair(currency.BTC, currency.AUD),
PostOnly: true,
})
if !errors.Is(err, order.ErrTypeIsInvalid) {
t.Fatalf("received: '%v' but expected: '%v'", err, order.ErrTypeIsInvalid)
}
_, err = b.SubmitOrder(context.Background(), &order.Submit{
Price: 100,
Amount: 1,
Type: order.Limit,
AssetType: asset.Spot,
Side: order.AnySide,
Pair: currency.NewPair(currency.BTC, currency.AUD),
PostOnly: true,
})
if !errors.Is(err, order.ErrSideIsInvalid) {
t.Fatalf("received: '%v' but expected: '%v'", err, order.ErrSideIsInvalid)
}

if !areTestAPIKeysSet() || !canManipulateRealOrders {
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
}
_, err := b.NewOrder(context.Background(),
BTCAUD, 100, 1, limit, bid, 0, 0, "", true, "", "")
_, err = b.SubmitOrder(context.Background(), &order.Submit{
Price: 100,
Amount: 1,
Type: order.Limit,
AssetType: asset.Spot,
Side: order.Bid,
Pair: currency.NewPair(currency.BTC, currency.AUD),
PostOnly: true,
})
if err != nil {
t.Error(err)
}
_, err = b.NewOrder(context.Background(),
BTCAUD, 100, 1, "invalid", bid, 0, 0, "", true, "", "")
if err == nil {
t.Error("expected an error due to invalid ordertype")
}

func TestNewOrder(t *testing.T) {
if !areTestAPIKeysSet() || !canManipulateRealOrders {
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
}
_, err = b.NewOrder(context.Background(),
BTCAUD, 100, 1, limit, "invalid", 0, 0, "", true, "", "")
if err == nil {
t.Error("expected an error due to invalid orderside")
_, err := b.NewOrder(context.Background(), 100, 1, 0, 0, BTCAUD, limit, bidSide, "", "", "", true)
if err != nil {
t.Error(err)
}
}

Expand Down Expand Up @@ -899,3 +931,100 @@ func TestTrim(t *testing.T) {
})
}
}

func TestFormatOrderType(t *testing.T) {
t.Parallel()
_, err := b.formatOrderType(order.Type("SWOOON"))
if !errors.Is(err, order.ErrTypeIsInvalid) {
t.Fatalf("received: '%v' but expected: '%v'", err, order.ErrTypeIsInvalid)
}

r, err := b.formatOrderType(order.Limit)
if !errors.Is(err, nil) {
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
}

if r != limit {
t.Fatal("unexpected value")
}

r, err = b.formatOrderType(order.Market)
if !errors.Is(err, nil) {
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
}

if r != market {
t.Fatal("unexpected value")
}

r, err = b.formatOrderType(order.StopLimit)
if !errors.Is(err, nil) {
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
}

if r != stopLimit {
t.Fatal("unexpected value")
}

r, err = b.formatOrderType(order.Stop)
if !errors.Is(err, nil) {
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
}

if r != stop {
t.Fatal("unexpected value")
}

r, err = b.formatOrderType(order.TakeProfit)
if !errors.Is(err, nil) {
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
}

if r != takeProfit {
t.Fatal("unexpected value")
}
}

func TestFormatOrderSide(t *testing.T) {
t.Parallel()
_, err := b.formatOrderSide("invalid")
if !errors.Is(err, order.ErrSideIsInvalid) {
t.Fatalf("received: '%v' but expected: '%v'", err, order.ErrSideIsInvalid)
}

f, err := b.formatOrderSide(order.Bid)
if !errors.Is(err, nil) {
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
}

if f != bidSide {
t.Fatal("unexpected value")
}

f, err = b.formatOrderSide(order.Ask)
if !errors.Is(err, nil) {
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
}

if f != askSide {
t.Fatal("unexpected value")
}
}

func TestGetTimeInForce(t *testing.T) {
t.Parallel()
f := b.getTimeInForce(&order.Submit{})
if f != "" {
t.Fatal("unexpected value")
}

f = b.getTimeInForce(&order.Submit{ImmediateOrCancel: true})
if f != immediateOrCancel {
t.Fatalf("received: '%v' but expected: '%v'", f, immediateOrCancel)
}

f = b.getTimeInForce(&order.Submit{FillOrKill: true})
if f != fillOrKill {
t.Fatalf("received: '%v' but expected: '%v'", f, fillOrKill)
}
}
2 changes: 2 additions & 0 deletions exchanges/btcmarkets/btcmarkets_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ type OrderData struct {
Amount float64 `json:"amount,string"`
OpenAmount float64 `json:"openAmount,string"`
Status string `json:"status"`
TargetAmount float64 `json:"targetAmount,string"`
TimeInForce string `json:"timeInForce"`
}

// CancelOrderResp stores data for cancelled orders
Expand Down
42 changes: 25 additions & 17 deletions exchanges/btcmarkets/btcmarkets_wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -423,16 +423,14 @@ func (b *BTCMarkets) UpdateAccountInfo(ctx context.Context, assetType asset.Item
return resp, err
}
var acc account.SubAccount
for key := range data {
c := currency.NewCode(data[key].AssetName)
hold := data[key].Locked
total := data[key].Balance
acc.Currencies = append(acc.Currencies,
account.Balance{CurrencyName: c,
Total: total,
Hold: hold,
Free: total - hold,
})
acc.AssetType = assetType
for x := range data {
acc.Currencies = append(acc.Currencies, account.Balance{
CurrencyName: currency.NewCode(data[x].AssetName),
Total: data[x].Balance,
Hold: data[x].Locked,
Free: data[x].Available,
})
}
resp.Accounts = append(resp.Accounts, acc)
resp.Exchange = b.Name
Expand Down Expand Up @@ -532,18 +530,28 @@ func (b *BTCMarkets) SubmitOrder(ctx context.Context, s *order.Submit) (order.Su
return resp, err
}

fOrderType, err := b.formatOrderType(s.Type)
if err != nil {
return resp, err
}

fOrderSide, err := b.formatOrderSide(s.Side)
if err != nil {
return resp, err
}

tempResp, err := b.NewOrder(ctx,
fpair.String(),
s.Price,
s.Amount,
s.Type.String(),
s.Side.String(),
s.TriggerPrice,
s.TargetAmount,
"",
false,
s.QuoteAmount,
fpair.String(),
fOrderType,
fOrderSide,
b.getTimeInForce(s),
"",
s.ClientID)
s.ClientID,
s.PostOnly)
if err != nil {
return resp, err
}
Expand Down
Loading

0 comments on commit 022001f

Please sign in to comment.