orders: Add methods to derive SubmitResponse and Detail types (#955)

* orders: deprecate SubmitResponse return and change to *order.Detail construct detail from order.Submit struct

* orders: add coverage, fix tests

* coinut: rm test for checking

* orders: revert change for return and change field ID to a more explicit name OrderID

* orders: Add method to see if the order was placed

* order: change field name in Cancel type to be more explicit

* orders: standardize field -> OrderID

* backtester: populate change

* orders: add test

* gctscript: fix field name

* linter: fix issues

* linter: more fixes

* linter: forever

* exchanges_tests: populate order.Submit field exchange name

* Update exchanges/order/order_types.go

Co-authored-by: Scott <gloriousCode@users.noreply.github.com>

* Update exchanges/order/orders.go

Co-authored-by: Scott <gloriousCode@users.noreply.github.com>

* glorious: nits

* glorious: nits

* thrasher: nits

Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io>
Co-authored-by: Scott <gloriousCode@users.noreply.github.com>
This commit is contained in:
Ryan O'Hara-Reid
2022-06-06 11:52:15 +10:00
committed by GitHub
parent 85da9b7166
commit a12cd3d733
95 changed files with 1377 additions and 1170 deletions

View File

@@ -173,7 +173,7 @@ func (m *OrderManager) Cancel(ctx context.Context, cancel *order.Cancel) error {
err = errors.New("order exchange name is empty")
return err
}
if cancel.ID == "" {
if cancel.OrderID == "" {
err = errors.New("order id is empty")
return err
}
@@ -189,16 +189,17 @@ func (m *OrderManager) Cancel(ctx context.Context, cancel *order.Cancel) error {
}
log.Debugf(log.OrderMgr, "Order manager: Cancelling order ID %v [%+v]",
cancel.ID, cancel)
cancel.OrderID, cancel)
err = exch.CancelOrder(ctx, cancel)
if err != nil {
err = fmt.Errorf("%v - Failed to cancel order: %w", cancel.Exchange, err)
return err
}
od, err := m.orderStore.getByExchangeAndID(cancel.Exchange, cancel.ID)
od, err := m.orderStore.getByExchangeAndID(cancel.Exchange, cancel.OrderID)
if err != nil {
err = fmt.Errorf("%v - Failed to retrieve order %v to update cancelled status: %w", cancel.Exchange, cancel.ID, err)
err = fmt.Errorf("%v - Failed to retrieve order %v to update cancelled status: %w",
cancel.Exchange, cancel.OrderID, err)
return err
}
od.Status = order.Cancelled
@@ -209,7 +210,7 @@ func (m *OrderManager) Cancel(ctx context.Context, cancel *order.Cancel) error {
}
msg := fmt.Sprintf("Order manager: Exchange %s order ID=%v cancelled.",
od.Exchange, od.ID)
od.Exchange, od.OrderID)
log.Debugln(log.OrderMgr, msg)
m.orderStore.commsManager.PushEvent(base.Event{Type: "order", Message: msg})
return nil
@@ -350,7 +351,7 @@ func (m *OrderManager) Modify(ctx context.Context, mod *order.Modify) (*order.Mo
}
// Fetch details from locally managed order store.
det, err := m.orderStore.getByExchangeAndID(mod.Exchange, mod.ID)
det, err := m.orderStore.getByExchangeAndID(mod.Exchange, mod.OrderID)
if det == nil || err != nil {
return nil, fmt.Errorf("order does not exist: %w", err)
}
@@ -381,7 +382,7 @@ func (m *OrderManager) Modify(ctx context.Context, mod *order.Modify) (*order.Mo
message := fmt.Sprintf(
"Order manager: Exchange %s order ID=%v: failed to modify",
mod.Exchange,
mod.ID,
mod.OrderID,
)
m.orderStore.commsManager.PushEvent(base.Event{
Type: "order",
@@ -394,7 +395,7 @@ func (m *OrderManager) Modify(ctx context.Context, mod *order.Modify) (*order.Mo
//
// XXX: This comes with a race condition, because [request -> changes] are not
// atomic.
err = m.orderStore.modifyExisting(mod.ID, res)
err = m.orderStore.modifyExisting(mod.OrderID, res)
// Notify observers.
var message string
@@ -458,12 +459,12 @@ func (m *OrderManager) Submit(ctx context.Context, newOrder *order.Submit) (*Ord
return nil, err
}
return m.processSubmittedOrder(newOrder, result)
return m.processSubmittedOrder(result)
}
// SubmitFakeOrder runs through the same process as order submission
// but does not touch live endpoints
func (m *OrderManager) SubmitFakeOrder(newOrder *order.Submit, resultingOrder order.SubmitResponse, checkExchangeLimits bool) (*OrderSubmitResponse, error) {
func (m *OrderManager) SubmitFakeOrder(newOrder *order.Submit, resultingOrder *order.SubmitResponse, checkExchangeLimits bool) (*OrderSubmitResponse, error) {
if m == nil {
return nil, fmt.Errorf("order manager %w", ErrNilSubsystem)
}
@@ -494,7 +495,7 @@ func (m *OrderManager) SubmitFakeOrder(newOrder *order.Submit, resultingOrder or
err)
}
}
return m.processSubmittedOrder(newOrder, resultingOrder)
return m.processSubmittedOrder(resultingOrder)
}
// GetOrdersSnapshot returns a snapshot of all orders in the orderstore. It optionally filters any orders that do not match the status
@@ -542,82 +543,45 @@ func (m *OrderManager) GetOrdersActive(f *order.Filter) ([]order.Detail, error)
}
// processSubmittedOrder adds a new order to the manager
func (m *OrderManager) processSubmittedOrder(newOrder *order.Submit, result order.SubmitResponse) (*OrderSubmitResponse, error) {
if !result.IsOrderPlaced {
return nil, errUnableToPlaceOrder
func (m *OrderManager) processSubmittedOrder(newOrderResp *order.SubmitResponse) (*OrderSubmitResponse, error) {
if newOrderResp == nil {
return nil, order.ErrOrderDetailIsNil
}
id, err := uuid.NewV4()
if err != nil {
log.Warnf(log.OrderMgr,
"Order manager: Unable to generate UUID. Err: %s",
err)
log.Warnf(log.OrderMgr, "Order manager: Unable to generate UUID. Err: %s", err)
}
if newOrder.Date.IsZero() {
newOrder.Date = time.Now()
detail, err := newOrderResp.DeriveDetail(id)
if err != nil {
return nil, err
}
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)
detail.Exchange,
detail.OrderID,
detail.InternalOrderID.String(),
detail.Pair,
detail.Price,
detail.Amount,
detail.QuoteAmount,
detail.Side,
detail.Type,
detail.Date)
log.Debugln(log.OrderMgr, msg)
m.orderStore.commsManager.PushEvent(base.Event{
Type: "order",
Message: msg,
})
status := order.New
if result.FullyMatched {
status = order.Filled
}
err = m.orderStore.add(&order.Detail{
ImmediateOrCancel: newOrder.ImmediateOrCancel,
HiddenOrder: newOrder.HiddenOrder,
FillOrKill: newOrder.FillOrKill,
PostOnly: newOrder.PostOnly,
Price: newOrder.Price,
Amount: newOrder.Amount,
LimitPriceUpper: newOrder.LimitPriceUpper,
LimitPriceLower: newOrder.LimitPriceLower,
TriggerPrice: newOrder.TriggerPrice,
QuoteAmount: newOrder.QuoteAmount,
ExecutedAmount: newOrder.ExecutedAmount,
RemainingAmount: newOrder.RemainingAmount,
Fee: newOrder.Fee,
Exchange: newOrder.Exchange,
InternalOrderID: id.String(),
ID: result.OrderID,
AccountID: newOrder.AccountID,
ClientID: newOrder.ClientID,
ClientOrderID: newOrder.ClientOrderID,
WalletAddress: newOrder.WalletAddress,
Type: newOrder.Type,
Side: newOrder.Side,
Status: status,
AssetType: newOrder.AssetType,
Date: time.Now(),
LastUpdated: time.Now(),
Pair: newOrder.Pair,
Leverage: newOrder.Leverage,
})
if err != nil {
return nil, fmt.Errorf("unable to add %v order %v to orderStore: %s", newOrder.Exchange, result.OrderID, err)
if m.orderStore.commsManager != nil {
m.orderStore.commsManager.PushEvent(base.Event{Type: "order", Message: msg})
}
return &OrderSubmitResponse{
SubmitResponse: order.SubmitResponse{
IsOrderPlaced: result.IsOrderPlaced,
OrderID: result.OrderID,
},
InternalOrderID: id.String(),
}, nil
err = m.orderStore.add(detail.CopyToPointer())
if err != nil {
return nil, fmt.Errorf("unable to add %v order %v to orderStore: %s",
detail.Exchange, detail.OrderID, err)
}
return &OrderSubmitResponse{Detail: detail, InternalOrderID: id.String()}, nil
}
// processOrders iterates over all exchange orders via API
@@ -730,7 +694,7 @@ func (m *OrderManager) FetchAndUpdateExchangeOrder(exch exchange.IBotExchange, o
if ord == nil {
return errors.New("order manager: Order is nil")
}
fetchedOrder, err := exch.GetOrderInfo(context.TODO(), ord.ID, ord.Pair, assetType)
fetchedOrder, err := exch.GetOrderInfo(context.TODO(), ord.OrderID, ord.Pair, assetType)
if err != nil {
ord.Status = order.UnknownStatus
return err
@@ -765,14 +729,7 @@ func (m *OrderManager) GetByExchangeAndID(exchangeName, id string) (*order.Detai
if atomic.LoadInt32(&m.started) == 0 {
return nil, fmt.Errorf("order manager %w", ErrSubSystemNotStarted)
}
o, err := m.orderStore.getByExchangeAndID(exchangeName, id)
if err != nil {
return nil, err
}
var cpy order.Detail
cpy.UpdateOrderFromDetail(o)
return &cpy, nil
return m.orderStore.getByExchangeAndID(exchangeName, id)
}
// UpdateExistingOrder will update an existing order in the orderstore
@@ -813,7 +770,7 @@ func (m *OrderManager) UpsertOrder(od *order.Detail) (resp *OrderUpsertResponse,
if err != nil {
msg = fmt.Sprintf(
"Order manager: Exchange %s unable to upsert order ID=%v internal ID=%v pair=%v price=%.8f amount=%.8f side=%v type=%v status=%v: %s",
od.Exchange, od.ID, od.InternalOrderID, od.Pair, od.Price, od.Amount, od.Side, od.Type, od.Status, err)
od.Exchange, od.OrderID, od.InternalOrderID, od.Pair, od.Price, od.Amount, od.Side, od.Type, od.Status, err)
return nil, err
}
@@ -822,7 +779,7 @@ func (m *OrderManager) UpsertOrder(od *order.Detail) (resp *OrderUpsertResponse,
status = "added"
}
msg = fmt.Sprintf("Order manager: Exchange %s %s order ID=%v internal ID=%v pair=%v price=%.8f amount=%.8f side=%v type=%v status=%v.",
upsertResponse.OrderDetails.Exchange, status, upsertResponse.OrderDetails.ID, upsertResponse.OrderDetails.InternalOrderID,
upsertResponse.OrderDetails.Exchange, status, upsertResponse.OrderDetails.OrderID, upsertResponse.OrderDetails.InternalOrderID,
upsertResponse.OrderDetails.Pair, upsertResponse.OrderDetails.Price, upsertResponse.OrderDetails.Amount,
upsertResponse.OrderDetails.Side, upsertResponse.OrderDetails.Type, upsertResponse.OrderDetails.Status)
if upsertResponse.IsNewOrder {
@@ -854,7 +811,7 @@ func (s *store) getByExchangeAndID(exchange, id string) (*order.Detail, error) {
}
for x := range r {
if r[x].ID == id {
if r[x].OrderID == id {
return r[x].CopyToPointer(), nil
}
}
@@ -874,14 +831,17 @@ func (s *store) updateExisting(od *order.Detail) error {
return ErrExchangeNotFound
}
for x := range r {
if r[x].ID != od.ID {
if r[x].OrderID != od.OrderID {
continue
}
r[x].UpdateOrderFromDetail(od)
err := r[x].UpdateOrderFromDetail(od)
if err != nil {
return err
}
if !r[x].AssetType.IsFutures() {
return nil
}
err := s.futuresPositionController.TrackNewOrder(r[x])
err = s.futuresPositionController.TrackNewOrder(r[x])
if err != nil && !errors.Is(err, order.ErrPositionClosed) {
return err
}
@@ -900,7 +860,7 @@ func (s *store) modifyExisting(id string, mod *order.ModifyResponse) error {
return ErrExchangeNotFound
}
for x := range r {
if r[x].ID != id {
if r[x].OrderID != id {
continue
}
r[x].UpdateOrderFromModifyResponse(mod)
@@ -935,18 +895,21 @@ func (s *store) upsert(od *order.Detail) (*OrderUpsertResponse, error) {
return nil, err
}
}
r, ok := s.Orders[lName]
if !ok {
od.GenerateInternalOrderID()
s.Orders[lName] = []*order.Detail{od}
return &OrderUpsertResponse{OrderDetails: od.Copy(), IsNewOrder: true}, nil
}
for x := range r {
if r[x].ID != od.ID {
// TODO: Return pointer to slice because new orders we are accessing map
// twice for lookup.
exchangeOrders := s.Orders[lName]
for x := range exchangeOrders {
if exchangeOrders[x].OrderID != od.OrderID {
continue
}
r[x].UpdateOrderFromDetail(od)
return &OrderUpsertResponse{OrderDetails: r[x].Copy(), IsNewOrder: false}, nil
err := exchangeOrders[x].UpdateOrderFromDetail(od)
if err != nil {
return nil, err
}
return &OrderUpsertResponse{
OrderDetails: exchangeOrders[x].Copy(),
IsNewOrder: false,
}, nil
}
// Untracked websocket orders will not have internalIDs yet
od.GenerateInternalOrderID()
@@ -961,13 +924,9 @@ func (s *store) exists(det *order.Detail) bool {
}
s.m.RLock()
defer s.m.RUnlock()
r, ok := s.Orders[strings.ToLower(det.Exchange)]
if !ok {
return false
}
for x := range r {
if r[x].ID == det.ID {
exchangeOrders := s.Orders[strings.ToLower(det.Exchange)]
for x := range exchangeOrders {
if exchangeOrders[x].OrderID == det.OrderID {
return true
}
}
@@ -979,21 +938,20 @@ func (s *store) add(det *order.Detail) error {
if det == nil {
return errNilOrder
}
_, err := s.exchangeManager.GetExchangeByName(det.Exchange)
name := strings.ToLower(det.Exchange)
_, err := s.exchangeManager.GetExchangeByName(name)
if err != nil {
return err
}
if s.exists(det) {
if s.exists(det) { // TODO: Error on conflict; remove unnecessary locking.
return ErrOrdersAlreadyExists
}
// Untracked websocket orders will not have internalIDs yet
det.GenerateInternalOrderID()
s.m.Lock()
defer s.m.Unlock()
orders := s.Orders[strings.ToLower(det.Exchange)]
orders = append(orders, det)
s.Orders[strings.ToLower(det.Exchange)] = orders
s.Orders[name] = append(s.Orders[name], det)
if !det.AssetType.IsFutures() {
return nil
}

View File

@@ -45,7 +45,7 @@ func (f omfExchange) GetOrderInfo(ctx context.Context, orderID string, pair curr
Side: order.Buy,
Status: order.Active,
LastUpdated: time.Now().Add(-time.Hour),
ID: "Order1-unknown-to-active",
OrderID: "Order1-unknown-to-active",
}, nil
case "Order2-active-to-inactive":
return order.Detail{
@@ -56,13 +56,13 @@ func (f omfExchange) GetOrderInfo(ctx context.Context, orderID string, pair curr
Side: order.Sell,
Status: order.Cancelled,
LastUpdated: time.Now().Add(-time.Hour),
ID: "Order2-active-to-inactive",
OrderID: "Order2-active-to-inactive",
}, nil
}
return order.Detail{
Exchange: testExchange,
ID: orderID,
OrderID: orderID,
Pair: pair,
AssetType: assetType,
Status: order.Cancelled,
@@ -79,7 +79,7 @@ func (f omfExchange) GetActiveOrders(ctx context.Context, req *order.GetOrdersRe
Side: order.Sell,
Status: order.Active,
LastUpdated: time.Now().Add(-time.Hour),
ID: "Order3-unknown-to-active",
OrderID: "Order3-unknown-to-active",
}}, nil
}
@@ -228,14 +228,14 @@ func TestOrdersAdd(t *testing.T) {
m := OrdersSetup(t)
err := m.orderStore.add(&order.Detail{
Exchange: testExchange,
ID: "TestOrdersAdd",
OrderID: "TestOrdersAdd",
})
if err != nil {
t.Error(err)
}
err = m.orderStore.add(&order.Detail{
Exchange: "testTest",
ID: "TestOrdersAdd",
OrderID: "TestOrdersAdd",
})
if err == nil {
t.Error("Expected error from non existent exchange")
@@ -248,7 +248,7 @@ func TestOrdersAdd(t *testing.T) {
err = m.orderStore.add(&order.Detail{
Exchange: testExchange,
ID: "TestOrdersAdd",
OrderID: "TestOrdersAdd",
})
if err == nil {
t.Error("Expected error re-adding order")
@@ -259,7 +259,7 @@ func TestGetByExchangeAndID(t *testing.T) {
m := OrdersSetup(t)
err := m.orderStore.add(&order.Detail{
Exchange: testExchange,
ID: "TestGetByExchangeAndID",
OrderID: "TestGetByExchangeAndID",
})
if err != nil {
t.Error(err)
@@ -269,7 +269,7 @@ func TestGetByExchangeAndID(t *testing.T) {
if err != nil {
t.Error(err)
}
if o.ID != "TestGetByExchangeAndID" {
if o.OrderID != "TestGetByExchangeAndID" {
t.Error("Expected to retrieve order")
}
@@ -291,7 +291,7 @@ func TestExists(t *testing.T) {
}
o := &order.Detail{
Exchange: testExchange,
ID: "TestExists",
OrderID: "TestExists",
}
if err := m.orderStore.add(o); err != nil {
t.Error(err)
@@ -311,7 +311,7 @@ func TestStore_modifyOrder(t *testing.T) {
Exchange: testExchange,
AssetType: asset.Spot,
Pair: pair,
ID: "fake_order_id",
OrderID: "fake_order_id",
Price: 8,
Amount: 128,
@@ -322,10 +322,9 @@ func TestStore_modifyOrder(t *testing.T) {
err = m.orderStore.modifyExisting("fake_order_id", &order.ModifyResponse{
Exchange: testExchange,
OrderID: "another_fake_order_id",
Price: 16,
Amount: 256,
OrderID: "another_fake_order_id",
Price: 16,
Amount: 256,
})
if err != nil {
t.Error(err)
@@ -341,10 +340,10 @@ func TestStore_modifyOrder(t *testing.T) {
if det == nil || err != nil { //nolint:staticcheck,nolintlint // SA5011 Ignore the nil warnings
t.Fatal("Failed to fetch order details")
}
if det.ID != "another_fake_order_id" || det.Price != 16 || det.Amount != 256 { //nolint:staticcheck,nolintlint // SA5011 Ignore the nil warnings
if det.OrderID != "another_fake_order_id" || det.Price != 16 || det.Amount != 256 { //nolint:staticcheck,nolintlint // SA5011 Ignore the nil warnings
t.Errorf(
"have (%s,%f,%f), want (%s,%f,%f)",
det.ID, det.Price, det.Amount,
det.OrderID, det.Price, det.Amount,
"another_fake_order_id", 16., 256.,
)
}
@@ -371,25 +370,24 @@ func TestCancelOrder(t *testing.T) {
}
err = m.Cancel(context.Background(), &order.Cancel{
ID: "ID",
OrderID: "ID",
})
if err == nil {
t.Error("Expected error due to no Exchange")
}
err = m.Cancel(context.Background(),
&order.Cancel{
ID: "ID",
Exchange: testExchange,
AssetType: asset.Binary,
})
err = m.Cancel(context.Background(), &order.Cancel{
OrderID: "ID",
Exchange: testExchange,
AssetType: asset.Binary,
})
if err == nil {
t.Error("Expected error due to bad asset type")
}
o := &order.Detail{
Exchange: testExchange,
ID: "1337",
OrderID: "1337",
Status: order.New,
}
err = m.orderStore.add(o)
@@ -397,12 +395,11 @@ func TestCancelOrder(t *testing.T) {
t.Error(err)
}
err = m.Cancel(context.Background(),
&order.Cancel{
ID: "Unknown",
Exchange: testExchange,
AssetType: asset.Spot,
})
err = m.Cancel(context.Background(), &order.Cancel{
OrderID: "Unknown",
Exchange: testExchange,
AssetType: asset.Spot,
})
if err == nil {
t.Error("Expected error due to no order found")
}
@@ -414,7 +411,7 @@ func TestCancelOrder(t *testing.T) {
cancel := &order.Cancel{
Exchange: testExchange,
ID: "1337",
OrderID: "1337",
Side: order.Sell,
AssetType: asset.Spot,
Pair: pair,
@@ -442,7 +439,7 @@ func TestGetOrderInfo(t *testing.T) {
if err != nil {
t.Error(err)
}
if result.ID != "1337" {
if result.OrderID != "1337" {
t.Error("unexpected order returned")
}
@@ -451,7 +448,7 @@ func TestGetOrderInfo(t *testing.T) {
if err != nil {
t.Error(err)
}
if result.ID != "1337" {
if result.OrderID != "1337" {
t.Error("unexpected order returned")
}
}
@@ -460,7 +457,7 @@ func TestCancelAllOrders(t *testing.T) {
m := OrdersSetup(t)
o := &order.Detail{
Exchange: testExchange,
ID: "TestCancelAllOrders",
OrderID: "TestCancelAllOrders",
Status: order.New,
}
if err := m.orderStore.add(o); err != nil {
@@ -499,12 +496,7 @@ func TestSubmit(t *testing.T) {
t.Error("Expected error from nil order")
}
o := &order.Submit{
Exchange: "",
ID: "FakePassingExchangeOrder",
Status: order.New,
Type: order.Market,
}
o := &order.Submit{Type: order.Market}
_, err = m.Submit(context.Background(), o)
if err == nil {
t.Error("Expected error from empty exchange")
@@ -566,7 +558,7 @@ func TestSubmit(t *testing.T) {
err = m.orderStore.add(&order.Detail{
Exchange: testExchange,
ID: "FakePassingExchangeOrder",
OrderID: "FakePassingExchangeOrder",
})
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
@@ -576,7 +568,7 @@ func TestSubmit(t *testing.T) {
if err != nil {
t.Error(err)
}
if o2.InternalOrderID == "" {
if o2.InternalOrderID.IsNil() {
t.Error("Failed to assign internal order id")
}
}
@@ -594,7 +586,7 @@ func TestOrderManager_Modify(t *testing.T) {
Exchange: testExchange,
AssetType: asset.Spot,
Pair: pair,
ID: "fake_order_id",
OrderID: "fake_order_id",
Price: 8,
Amount: 128,
})
@@ -620,10 +612,10 @@ func TestOrderManager_Modify(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if det.ID != resp.OrderID || det.Price != price || det.Amount != amount {
if det.OrderID != resp.OrderID || det.Price != price || det.Amount != amount {
t.Errorf(
"have (%s,%f,%f), want (%s,%f,%f)",
det.ID, det.Price, det.Amount,
det.OrderID, det.Price, det.Amount,
resp.OrderID, price, amount,
)
}
@@ -634,7 +626,7 @@ func TestOrderManager_Modify(t *testing.T) {
Exchange: testExchange,
AssetType: asset.Spot,
Pair: pair,
ID: "fake_order_id",
OrderID: "fake_order_id",
// These fields modify the order.
Price: 0,
Amount: 0,
@@ -642,7 +634,7 @@ func TestOrderManager_Modify(t *testing.T) {
// [1] Test if nonexistent order returns an error.
one := model
one.ID = "nonexistent_order_id"
one.OrderID = "nonexistent_order_id"
f(one, true, 0, 0)
// [2] Test if price of 0 is ignored.
@@ -752,7 +744,7 @@ func TestProcessOrders(t *testing.T) {
Side: order.Buy,
Status: order.UnknownStatus,
LastUpdated: time.Now().Add(-time.Hour),
ID: "Order1-unknown-to-active",
OrderID: "Order1-unknown-to-active",
},
{
Exchange: testExchange,
@@ -762,7 +754,7 @@ func TestProcessOrders(t *testing.T) {
Side: order.Sell,
Status: order.Active,
LastUpdated: time.Now().Add(-time.Hour),
ID: "Order2-active-to-inactive",
OrderID: "Order2-active-to-inactive",
},
{
Exchange: testExchange,
@@ -772,7 +764,7 @@ func TestProcessOrders(t *testing.T) {
Side: order.Sell,
Status: order.UnknownStatus,
LastUpdated: time.Now().Add(-time.Hour),
ID: "Order3-unknown-to-active",
OrderID: "Order3-unknown-to-active",
},
}
for i := range orders {
@@ -785,7 +777,7 @@ func TestProcessOrders(t *testing.T) {
// Order1 is not returned by exch.GetActiveOrders()
// It will be fetched by exch.GetOrderInfo(), which will say it is active
res, err := m.GetOrdersFiltered(&order.Filter{ID: "Order1-unknown-to-active"})
res, err := m.GetOrdersFiltered(&order.Filter{OrderID: "Order1-unknown-to-active"})
if err != nil {
t.Error(err)
}
@@ -798,7 +790,7 @@ func TestProcessOrders(t *testing.T) {
// Order2 is not returned by exch.GetActiveOrders()
// It will be fetched by exch.GetOrderInfo(), which will say it is cancelled
res, err = m.GetOrdersFiltered(&order.Filter{ID: "Order2-active-to-inactive"})
res, err = m.GetOrdersFiltered(&order.Filter{OrderID: "Order2-active-to-inactive"})
if err != nil {
t.Error(err)
}
@@ -810,7 +802,7 @@ func TestProcessOrders(t *testing.T) {
}
// Order3 is returned by exch.GetActiveOrders(), which will say it is active
res, err = m.GetOrdersFiltered(&order.Filter{ID: "Order3-unknown-to-active"})
res, err = m.GetOrdersFiltered(&order.Filter{OrderID: "Order3-unknown-to-active"})
if err != nil {
t.Error(err)
}
@@ -831,11 +823,11 @@ func TestGetOrdersFiltered(t *testing.T) {
orders := []order.Detail{
{
Exchange: testExchange,
ID: "Test1",
OrderID: "Test1",
},
{
Exchange: testExchange,
ID: "Test2",
OrderID: "Test2",
},
}
for i := range orders {
@@ -843,7 +835,7 @@ func TestGetOrdersFiltered(t *testing.T) {
t.Error(err)
}
}
res, err := m.GetOrdersFiltered(&order.Filter{ID: "Test2"})
res, err := m.GetOrdersFiltered(&order.Filter{OrderID: "Test2"})
if err != nil {
t.Error(err)
}
@@ -863,11 +855,11 @@ func Test_getFilteredOrders(t *testing.T) {
orders := []order.Detail{
{
Exchange: testExchange,
ID: "Test1",
OrderID: "Test1",
},
{
Exchange: testExchange,
ID: "Test2",
OrderID: "Test2",
},
}
for i := range orders {
@@ -875,7 +867,7 @@ func Test_getFilteredOrders(t *testing.T) {
t.Error(err)
}
}
res, err := m.orderStore.getFilteredOrders(&order.Filter{ID: "Test1"})
res, err := m.orderStore.getFilteredOrders(&order.Filter{OrderID: "Test1"})
if err != nil {
t.Error(err)
}
@@ -893,14 +885,14 @@ func TestGetOrdersActive(t *testing.T) {
Amount: 1.0,
Side: order.Buy,
Status: order.Cancelled,
ID: "Test1",
OrderID: "Test1",
},
{
Exchange: testExchange,
Amount: 1.0,
Side: order.Sell,
Status: order.Active,
ID: "Test2",
OrderID: "Test2",
},
}
for i := range orders {
@@ -940,12 +932,12 @@ func Test_processMatchingOrders(t *testing.T) {
orders := []order.Detail{
{
Exchange: testExchange,
ID: "Test2",
OrderID: "Test2",
LastUpdated: time.Now(),
},
{
Exchange: testExchange,
ID: "Test4",
OrderID: "Test4",
LastUpdated: time.Now().Add(-time.Hour),
},
}
@@ -960,7 +952,7 @@ func Test_processMatchingOrders(t *testing.T) {
if len(res) != 1 {
t.Errorf("Expected 1 result, got: %d", len(res))
}
if res[0].ID != "Test4" {
if res[0].OrderID != "Test4" {
t.Error("Order Test4 should have been fetched and updated")
}
}
@@ -980,7 +972,7 @@ func TestFetchAndUpdateExchangeOrder(t *testing.T) {
Amount: 1.0,
Side: order.Sell,
Status: order.Active,
ID: "Test",
OrderID: "Test",
}
err = m.FetchAndUpdateExchangeOrder(exch, o, asset.Spot)
if err != nil {
@@ -1020,14 +1012,14 @@ func Test_getActiveOrders(t *testing.T) {
Amount: 1.0,
Side: order.Buy,
Status: order.Cancelled,
ID: "Test1",
OrderID: "Test1",
},
{
Exchange: testExchange,
Amount: 1.0,
Side: order.Sell,
Status: order.Active,
ID: "Test2",
OrderID: "Test2",
},
}
for i := range orders {
@@ -1074,7 +1066,7 @@ func TestGetFuturesPositionsForExchange(t *testing.T) {
}
err = o.orderStore.futuresPositionController.TrackNewOrder(&order.Detail{
ID: "test",
OrderID: "test",
Date: time.Now(),
Exchange: "test",
AssetType: asset.Futures,
@@ -1125,7 +1117,7 @@ func TestClearFuturesPositionsForExchange(t *testing.T) {
}
err = o.orderStore.futuresPositionController.TrackNewOrder(&order.Detail{
ID: "test",
OrderID: "test",
Date: time.Now(),
Exchange: "test",
AssetType: asset.Futures,
@@ -1180,7 +1172,7 @@ func TestUpdateOpenPositionUnrealisedPNL(t *testing.T) {
}
err = o.orderStore.futuresPositionController.TrackNewOrder(&order.Detail{
ID: "test",
OrderID: "test",
Date: time.Now(),
Exchange: "test",
AssetType: asset.Futures,
@@ -1209,7 +1201,7 @@ func TestUpdateOpenPositionUnrealisedPNL(t *testing.T) {
func TestSubmitFakeOrder(t *testing.T) {
t.Parallel()
o := &OrderManager{}
resp := order.SubmitResponse{}
resp := &order.SubmitResponse{}
_, err := o.SubmitFakeOrder(nil, resp, false)
if !errors.Is(err, ErrSubSystemNotStarted) {
t.Errorf("received '%v', expected '%v'", err, ErrSubSystemNotStarted)
@@ -1240,13 +1232,12 @@ func TestSubmitFakeOrder(t *testing.T) {
em.Add(exch)
o.orderStore.exchangeManager = em
_, err = o.SubmitFakeOrder(ord, resp, false)
if !errors.Is(err, errUnableToPlaceOrder) {
t.Errorf("received '%v', expected '%v'", err, errUnableToPlaceOrder)
resp, err = ord.DeriveSubmitResponse("1234")
if err != nil {
t.Fatal(err)
}
resp.IsOrderPlaced = true
resp.FullyMatched = true
resp.Status = order.Filled
o.orderStore.commsManager = &CommunicationManager{}
o.orderStore.Orders = make(map[string][]*order.Detail)
_, err = o.SubmitFakeOrder(ord, resp, false)
@@ -1295,7 +1286,7 @@ func TestUpdateExisting(t *testing.T) {
t.Errorf("received '%v', expected '%v'", err, ErrOrderNotFound)
}
od.AssetType = asset.Futures
od.ID = "123"
od.OrderID = "123"
od.Pair = currency.NewPair(currency.BTC, currency.USDT)
od.Side = order.Buy
od.Type = order.Market

View File

@@ -24,7 +24,6 @@ var (
errNilCommunicationsManager = errors.New("cannot start with nil communications manager")
errNilOrder = errors.New("nil order received")
errFuturesTrackerNotSetup = errors.New("futures position tracker not setup")
errUnableToPlaceOrder = errors.New("cannot process order, order not placed")
orderManagerDelay = time.Second * 10
)
@@ -61,7 +60,7 @@ type OrderManager struct {
// OrderSubmitResponse contains the order response along with an internal order ID
type OrderSubmitResponse struct {
order.SubmitResponse
*order.Detail
InternalOrderID string
}

View File

@@ -970,7 +970,7 @@ func (s *RPCServer) GetOrders(ctx context.Context, r *gctrpc.GetOrdersRequest) (
}
o := &gctrpc.OrderDetails{
Exchange: r.Exchange,
Id: resp[x].ID,
Id: resp[x].OrderID,
ClientOrderId: resp[x].ClientOrderID,
BaseCurrency: resp[x].Pair.Base.String(),
QuoteCurrency: resp[x].Pair.Quote.String(),
@@ -1059,7 +1059,7 @@ func (s *RPCServer) GetManagedOrders(_ context.Context, r *gctrpc.GetOrdersReque
}
o := &gctrpc.OrderDetails{
Exchange: r.Exchange,
Id: resp[x].ID,
Id: resp[x].OrderID,
ClientOrderId: resp[x].ClientOrderID,
BaseCurrency: resp[x].Pair.Base.String(),
QuoteCurrency: resp[x].Pair.Quote.String(),
@@ -1150,7 +1150,7 @@ func (s *RPCServer) GetOrder(ctx context.Context, r *gctrpc.GetOrderRequest) (*g
return &gctrpc.OrderDetails{
Exchange: result.Exchange,
Id: result.ID,
Id: result.OrderID,
ClientOrderId: result.ClientOrderID,
BaseCurrency: result.Pair.Base.String(),
QuoteCurrency: result.Pair.Quote.String(),
@@ -1236,9 +1236,9 @@ func (s *RPCServer) SubmitOrder(ctx context.Context, r *gctrpc.SubmitOrderReques
return &gctrpc.SubmitOrderResponse{
OrderId: resp.OrderID,
OrderPlaced: resp.IsOrderPlaced,
OrderPlaced: resp.WasOrderPlaced(),
Trades: trades,
}, err
}, nil
}
// SimulateOrder simulates an order specified by exchange, currency pair and asset
@@ -1384,7 +1384,7 @@ func (s *RPCServer) CancelOrder(ctx context.Context, r *gctrpc.CancelOrderReques
&order.Cancel{
Exchange: r.Exchange,
AccountID: r.AccountId,
ID: r.OrderId,
OrderID: r.OrderId,
Side: side,
WalletAddress: r.WalletAddress,
Pair: p,
@@ -1434,7 +1434,7 @@ func (s *RPCServer) CancelBatchOrders(ctx context.Context, r *gctrpc.CancelBatch
status[orderID] = order.Cancelled.String()
request[x] = order.Cancel{
AccountID: r.AccountId,
ID: orderID,
OrderID: orderID,
Side: side,
WalletAddress: r.WalletAddress,
Pair: pair,
@@ -1495,17 +1495,14 @@ func (s *RPCServer) ModifyOrder(ctx context.Context, r *gctrpc.ModifyOrderReques
if err != nil {
return nil, err
}
mod := order.Modify{
resp, err := s.OrderManager.Modify(ctx, &order.Modify{
Exchange: r.Exchange,
AssetType: assetType,
Pair: pair,
ID: r.OrderId,
Amount: r.Amount,
Price: r.Price,
}
resp, err := s.OrderManager.Modify(ctx, &mod)
OrderID: r.OrderId,
Amount: r.Amount,
Price: r.Price,
})
if err != nil {
return nil, err
}
@@ -4304,7 +4301,7 @@ func (s *RPCServer) GetFuturesPositions(ctx context.Context, r *gctrpc.GetFuture
}
od := &gctrpc.OrderDetails{
Exchange: pos[i].Orders[j].Exchange,
Id: pos[i].Orders[j].ID,
Id: pos[i].Orders[j].OrderID,
ClientOrderId: pos[i].Orders[j].ClientOrderID,
BaseCurrency: pos[i].Orders[j].Pair.Base.String(),
QuoteCurrency: pos[i].Orders[j].Pair.Quote.String(),

View File

@@ -143,7 +143,7 @@ func (f fExchange) GetFuturesPositions(_ context.Context, a asset.Item, cp curre
Fee: 1.337,
FeeAsset: currency.Code{},
Exchange: f.GetName(),
ID: "test",
OrderID: "test",
Side: order.Long,
Status: order.Open,
AssetType: a,
@@ -1827,20 +1827,14 @@ func TestGetManagedOrders(t *testing.T) {
}
o := order.Detail{
Price: 100000,
Amount: 0.002,
Exchange: "Binance",
InternalOrderID: "",
ID: "",
ClientOrderID: "",
AccountID: "",
ClientID: "",
WalletAddress: "",
Type: order.Limit,
Side: order.Sell,
Status: order.New,
AssetType: asset.Spot,
Pair: currency.NewPair(currency.BTC, currency.USDT),
Price: 100000,
Amount: 0.002,
Exchange: "Binance",
Type: order.Limit,
Side: order.Sell,
Status: order.New,
AssetType: asset.Spot,
Pair: currency.NewPair(currency.BTC, currency.USDT),
}
err = om.Add(&o)
if err != nil {

View File

@@ -240,11 +240,14 @@ func (m *websocketRoutineManager) websocketDataHandler(exchName string, data int
}
m.printOrderSummary(d, false)
} else {
od, err := m.orderManager.GetByExchangeAndID(d.Exchange, d.ID)
od, err := m.orderManager.GetByExchangeAndID(d.Exchange, d.OrderID)
if err != nil {
return err
}
err = od.UpdateOrderFromDetail(d)
if err != nil {
return err
}
od.UpdateOrderFromDetail(d)
err = m.orderManager.UpdateExistingOrder(od)
if err != nil {
@@ -310,7 +313,7 @@ func (m *websocketRoutineManager) printOrderSummary(o *order.Detail, isUpdate bo
o.Status,
o.Type,
o.Side,
o.ID,
o.OrderID,
o.ClientOrderID,
o.Price,
o.Amount,

View File

@@ -174,7 +174,7 @@ func TestWebsocketRoutineManagerHandleData(t *testing.T) {
}
origOrder := &order.Detail{
Exchange: exchName,
ID: orderID,
OrderID: orderID,
Amount: 1337,
Price: 1337,
}
@@ -185,13 +185,13 @@ func TestWebsocketRoutineManagerHandleData(t *testing.T) {
// Send it again since it exists now
err = m.websocketDataHandler(exchName, &order.Detail{
Exchange: exchName,
ID: orderID,
OrderID: orderID,
Amount: 1338,
})
if err != nil {
t.Error(err)
}
updated, err := m.orderManager.GetByExchangeAndID(origOrder.Exchange, origOrder.ID)
updated, err := m.orderManager.GetByExchangeAndID(origOrder.Exchange, origOrder.OrderID)
if err != nil {
t.Error(err)
}
@@ -201,13 +201,13 @@ func TestWebsocketRoutineManagerHandleData(t *testing.T) {
err = m.websocketDataHandler(exchName, &order.Detail{
Exchange: "Bitstamp",
ID: orderID,
OrderID: orderID,
Status: order.Active,
})
if err != nil {
t.Error(err)
}
updated, err = m.orderManager.GetByExchangeAndID(origOrder.Exchange, origOrder.ID)
updated, err = m.orderManager.GetByExchangeAndID(origOrder.Exchange, origOrder.OrderID)
if err != nil {
t.Error(err)
}