Skip to content

Commit

Permalink
orders: Add AdjustBaseAmount (thrasher-corp#1181)
Browse files Browse the repository at this point in the history
* orders: Add AdjustBaseAmount method that alerts if non-fatal change occurs exchange side, adjust BTCM

* glorious: nits

* glorious: nits

* thrasher: nits

* Update exchanges/btcmarkets/btcmarkets_wrapper.go

Co-authored-by: Adrian Gallagher <[email protected]>

* Update exchanges/btcmarkets/btcmarkets_wrapper.go

Co-authored-by: Adrian Gallagher <[email protected]>

* thrasher: nits and whoopsie

* orders_test: fix

---------

Co-authored-by: Ryan O'Hara-Reid <[email protected]>
Co-authored-by: Adrian Gallagher <[email protected]>
  • Loading branch information
3 people authored May 12, 2023
1 parent db8735e commit 8309ddf
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 5 deletions.
24 changes: 23 additions & 1 deletion exchanges/btcmarkets/btcmarkets_wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,29 @@ func (b *BTCMarkets) SubmitOrder(ctx context.Context, s *order.Submit) (*order.S
if err != nil {
return nil, err
}
return s.DeriveSubmitResponse(tempResp.OrderID)

submitResp, err := s.DeriveSubmitResponse(tempResp.OrderID)
if err != nil {
return nil, err
}

if tempResp.Amount != 0 {
err = submitResp.AdjustBaseAmount(tempResp.Amount)
if err != nil {
log.Errorf(log.ExchangeSys, "Exchange %s: OrderID: %s base amount conversion error: %s\n", b.Name, submitResp.OrderID, err)
}
}

if tempResp.TargetAmount != 0 {
err = submitResp.AdjustQuoteAmount(tempResp.TargetAmount)
if err != nil {
log.Errorf(log.ExchangeSys, "Exchange %s: OrderID: %s quote amount conversion error: %s\n", b.Name, submitResp.OrderID, err)
}
}
// With market orders the price is optional, so we can set it to the
// actual price that was filled.
submitResp.Price = tempResp.Price
return submitResp, nil
}

// ModifyOrder will allow of changing orderbook placement and limit to
Expand Down
76 changes: 74 additions & 2 deletions exchanges/order/order_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1260,11 +1260,11 @@ func TestUpdateOrderFromDetail(t *testing.T) {

func TestClassificationError_Error(t *testing.T) {
class := ClassificationError{OrderID: "1337", Exchange: "test", Err: errors.New("test error")}
if class.Error() != "test - OrderID: 1337 classification error: test error" {
if class.Error() != "Exchange test: OrderID: 1337 classification error: test error" {
t.Fatal("unexpected output")
}
class.OrderID = ""
if class.Error() != "test - classification error: test error" {
if class.Error() != "Exchange test: classification error: test error" {
t.Fatal("unexpected output")
}
}
Expand Down Expand Up @@ -1959,3 +1959,75 @@ func TestIsValidOrderSubmissionSide(t *testing.T) {
t.Error("expected false")
}
}

func TestAdjustBaseAmount(t *testing.T) {
t.Parallel()

var s *SubmitResponse
err := s.AdjustBaseAmount(0)
if !errors.Is(err, errOrderSubmitResponseIsNil) {
t.Fatalf("received: '%v' but expected: '%v'", err, errOrderSubmitResponseIsNil)
}

s = &SubmitResponse{}
err = s.AdjustBaseAmount(0)
if !errors.Is(err, errAmountIsZero) {
t.Fatalf("received: '%v' but expected: '%v'", err, errAmountIsZero)
}

s.Amount = 1.7777777777
err = s.AdjustBaseAmount(1.7777777777)
if !errors.Is(err, nil) {
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
}

if s.Amount != 1.7777777777 {
t.Fatalf("received: '%v' but expected: '%v'", s.Amount, 1.7777777777)
}

s.Amount = 1.7777777777
err = s.AdjustBaseAmount(1.777)
if !errors.Is(err, nil) {
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
}

if s.Amount != 1.777 {
t.Fatalf("received: '%v' but expected: '%v'", s.Amount, 1.777)
}
}

func TestAdjustQuoteAmount(t *testing.T) {
t.Parallel()

var s *SubmitResponse
err := s.AdjustQuoteAmount(0)
if !errors.Is(err, errOrderSubmitResponseIsNil) {
t.Fatalf("received: '%v' but expected: '%v'", err, errOrderSubmitResponseIsNil)
}

s = &SubmitResponse{}
err = s.AdjustQuoteAmount(0)
if !errors.Is(err, errAmountIsZero) {
t.Fatalf("received: '%v' but expected: '%v'", err, errAmountIsZero)
}

s.QuoteAmount = 5.222222222222
err = s.AdjustQuoteAmount(5.222222222222)
if !errors.Is(err, nil) {
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
}

if s.QuoteAmount != 5.222222222222 {
t.Fatalf("received: '%v' but expected: '%v'", s.Amount, 5.222222222222)
}

s.QuoteAmount = 5.222222222222
err = s.AdjustQuoteAmount(5.22222222)
if !errors.Is(err, nil) {
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
}

if s.QuoteAmount != 5.22222222 {
t.Fatalf("received: '%v' but expected: '%v'", s.Amount, 5.22222222)
}
}
63 changes: 61 additions & 2 deletions exchanges/order/orders.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ var (
errOrderSubmitIsNil = errors.New("order submit is nil")
errOrderSubmitResponseIsNil = errors.New("order submit response is nil")
errOrderDetailIsNil = errors.New("order detail is nil")
errAmountIsZero = errors.New("amount is zero")
)

// IsValidOrderSubmissionSide validates that the order side is a valid submission direction
Expand Down Expand Up @@ -475,6 +476,64 @@ func (s *Submit) DeriveSubmitResponse(orderID string) (*SubmitResponse, error) {
}, nil
}

// AdjustBaseAmount will adjust the base amount of a submit response if the
// exchange has modified the amount. This is usually due to decimal place
// restrictions or rounding. This will return an error if the amount is zero
// or the submit response is nil.
func (s *SubmitResponse) AdjustBaseAmount(a float64) error {
if s == nil {
return errOrderSubmitResponseIsNil
}

if a <= 0 {
return errAmountIsZero
}

if s.Amount == a {
return nil
}

// Warning because amounts should conform to exchange requirements prior to
// call but this is not fatal.
log.Warnf(log.ExchangeSys, "Exchange %s: has adjusted OrderID: %s requested base amount from %v to %v",
s.Exchange,
s.OrderID,
s.Amount,
a)

s.Amount = a
return nil
}

// AdjustQuoteAmount will adjust the quote amount of a submit response if the
// exchange has modified the amount. This is usually due to decimal place
// restrictions or rounding. This will return an error if the amount is zero
// or the submit response is nil.
func (s *SubmitResponse) AdjustQuoteAmount(a float64) error {
if s == nil {
return errOrderSubmitResponseIsNil
}

if a <= 0 {
return errAmountIsZero
}

if s.QuoteAmount == a {
return nil
}

// Warning because amounts should conform to exchange requirements prior to
// call but this is not fatal.
log.Warnf(log.ExchangeSys, "Exchange %s: has adjusted OrderID: %s requested quote amount from %v to %v",
s.Exchange,
s.OrderID,
s.Amount,
a)

s.QuoteAmount = a
return nil
}

// DeriveDetail will construct an order detail when a successful submission
// has occurred. Has an optional parameter field internal uuid for internal
// management.
Expand Down Expand Up @@ -1069,12 +1128,12 @@ func StringToOrderStatus(status string) (Status, error) {

func (o *ClassificationError) Error() string {
if o.OrderID != "" {
return fmt.Sprintf("%s - OrderID: %s classification error: %v",
return fmt.Sprintf("Exchange %s: OrderID: %s classification error: %v",
o.Exchange,
o.OrderID,
o.Err)
}
return fmt.Sprintf("%s - classification error: %v",
return fmt.Sprintf("Exchange %s: classification error: %v",
o.Exchange,
o.Err)
}
Expand Down

0 comments on commit 8309ddf

Please sign in to comment.