mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 23:16:45 +00:00
* Initial REST managed order updating
* Apply gloriousCode's changes.go patch
* Update internal order ID handling
* Check error
* Replace string with string pointer
* Avoid nil pointers in upsert
* Update test for UpdateOrderFromDetail()
* Add tests for orders.go
* Remove unnecessary newline
* Address comments
* Add missing nil check
* Add tests for new functions in order_manager.go
* Remove empty line
* Change log level for updates from Info to Debug (keep added orders at Info)
* Initialize orders before running the timer
* [TEMP] Add verbosity for debugging
* Nil checking on exchangeManager in GetExchanges()
- exchangeManager.GetExchanges() and iExchangeManager.GetExchanges() return an error on nil
- bot.GetExchanges() wraps exchangeManager.GetExchanges() and returns an empty slice
* Revert b5afe1a46b
* Do not start the order manager runner thread
Instead, mark the order manager as running
* Remove redundant error.Is() and remove print wrapper on msg
* Add atomic blocker and waitgroup on processOrders()
* Disable unnecessary orderManager runner thread for rpcserver_test
* Remove redundant err from orderStore.getActiveOrders()
* [FIX] Populate requiresProcessing using UpsertResponse data instead of REST return data
.. because the data returned by the REST calls do not include the internal user ID's
* [TEST] Verify that processOrders() actually processes queried order data
* Remove leftover warning and add nil check on wg.Done()
* Apply suggestions from code review
Log category changes - as suggested
Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>
* Return when no exchanges available
Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>
This commit is contained in:
@@ -84,6 +84,7 @@ func (b *Bittrex) SetDefaults() {
|
||||
TradeFetching: true,
|
||||
OrderbookFetching: true,
|
||||
AutoPairUpdates: true,
|
||||
GetOrder: true,
|
||||
GetOrders: true,
|
||||
CancelOrder: true,
|
||||
CancelOrders: true,
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gofrs/uuid"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/validate"
|
||||
@@ -815,7 +816,7 @@ func TestUpdateOrderFromDetail(t *testing.T) {
|
||||
RemainingAmount: 0,
|
||||
Fee: 0,
|
||||
Exchange: "test",
|
||||
ID: "1",
|
||||
ID: "",
|
||||
AccountID: "",
|
||||
ClientID: "",
|
||||
WalletAddress: "",
|
||||
@@ -866,8 +867,8 @@ func TestUpdateOrderFromDetail(t *testing.T) {
|
||||
}
|
||||
|
||||
od.UpdateOrderFromDetail(&om)
|
||||
if od.InternalOrderID == "1" {
|
||||
t.Error("Should not be able to update the internal order ID")
|
||||
if od.InternalOrderID != "1" {
|
||||
t.Error("Failed to initialize the internal order ID")
|
||||
}
|
||||
if !od.ImmediateOrCancel {
|
||||
t.Error("Failed to update")
|
||||
@@ -987,6 +988,15 @@ func TestUpdateOrderFromDetail(t *testing.T) {
|
||||
if od.Trades[0].Amount != 1337 {
|
||||
t.Error("Failed to update trades")
|
||||
}
|
||||
|
||||
om = Detail{
|
||||
InternalOrderID: "2",
|
||||
}
|
||||
|
||||
od.UpdateOrderFromDetail(&om)
|
||||
if od.InternalOrderID == "2" {
|
||||
t.Error("Should not be able to update the internal order ID after initialization")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClassificationError_Error(t *testing.T) {
|
||||
@@ -1209,6 +1219,136 @@ func TestMatchFilter(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsActive(t *testing.T) {
|
||||
orders := map[int]Detail{
|
||||
0: {Amount: 0.0, Status: Active},
|
||||
1: {Amount: 1.0, ExecutedAmount: 0.9, Status: Active},
|
||||
2: {Amount: 1.0, ExecutedAmount: 1.0, Status: Active},
|
||||
3: {Amount: 1.0, ExecutedAmount: 1.1, Status: Active},
|
||||
}
|
||||
|
||||
amountTests := map[int]struct {
|
||||
o Detail
|
||||
expRes bool
|
||||
}{
|
||||
0: {orders[0], false},
|
||||
1: {orders[1], true},
|
||||
2: {orders[2], false},
|
||||
3: {orders[3], false},
|
||||
}
|
||||
// specific tests
|
||||
for num, tt := range amountTests {
|
||||
if tt.o.IsActive() != tt.expRes {
|
||||
t.Errorf("amountTests[%v] failed", num)
|
||||
}
|
||||
}
|
||||
|
||||
statusTests := map[int]struct {
|
||||
o Detail
|
||||
expRes bool
|
||||
}{
|
||||
0: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: AnyStatus}, true},
|
||||
1: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: New}, true},
|
||||
2: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: Active}, true},
|
||||
3: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: PartiallyCancelled}, false},
|
||||
4: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: PartiallyFilled}, true},
|
||||
5: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: Filled}, false},
|
||||
6: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: Cancelled}, false},
|
||||
7: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: PendingCancel}, true},
|
||||
8: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: InsufficientBalance}, false},
|
||||
9: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: MarketUnavailable}, false},
|
||||
10: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: Rejected}, false},
|
||||
11: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: Expired}, false},
|
||||
12: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: Hidden}, true},
|
||||
13: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: UnknownStatus}, true},
|
||||
14: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: Open}, true},
|
||||
15: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: AutoDeleverage}, true},
|
||||
16: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: Closed}, false},
|
||||
17: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: Pending}, true},
|
||||
}
|
||||
// specific tests
|
||||
for num, tt := range statusTests {
|
||||
if tt.o.IsActive() != tt.expRes {
|
||||
t.Errorf("statusTests[%v] failed", num)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsInctive(t *testing.T) {
|
||||
orders := map[int]Detail{
|
||||
0: {Amount: 0.0, Status: Active},
|
||||
1: {Amount: 1.0, ExecutedAmount: 0.9, Status: Active},
|
||||
2: {Amount: 1.0, ExecutedAmount: 1.0, Status: Active},
|
||||
3: {Amount: 1.0, ExecutedAmount: 1.1, Status: Active},
|
||||
}
|
||||
|
||||
amountTests := map[int]struct {
|
||||
o Detail
|
||||
expRes bool
|
||||
}{
|
||||
0: {orders[0], true},
|
||||
1: {orders[1], false},
|
||||
2: {orders[2], true},
|
||||
3: {orders[3], true},
|
||||
}
|
||||
// specific tests
|
||||
for num, tt := range amountTests {
|
||||
if tt.o.IsInactive() != tt.expRes {
|
||||
t.Errorf("amountTests[%v] failed", num)
|
||||
}
|
||||
}
|
||||
|
||||
statusTests := map[int]struct {
|
||||
o Detail
|
||||
expRes bool
|
||||
}{
|
||||
0: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: AnyStatus}, false},
|
||||
1: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: New}, false},
|
||||
2: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: Active}, false},
|
||||
3: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: PartiallyCancelled}, true},
|
||||
4: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: PartiallyFilled}, false},
|
||||
5: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: Filled}, true},
|
||||
6: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: Cancelled}, true},
|
||||
7: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: PendingCancel}, false},
|
||||
8: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: InsufficientBalance}, true},
|
||||
9: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: MarketUnavailable}, true},
|
||||
10: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: Rejected}, true},
|
||||
11: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: Expired}, true},
|
||||
12: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: Hidden}, false},
|
||||
13: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: UnknownStatus}, false},
|
||||
14: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: Open}, false},
|
||||
15: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: AutoDeleverage}, false},
|
||||
16: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: Closed}, true},
|
||||
17: {Detail{Amount: 1.0, ExecutedAmount: 0.0, Status: Pending}, false},
|
||||
}
|
||||
// specific tests
|
||||
for num, tt := range statusTests {
|
||||
if tt.o.IsInactive() != tt.expRes {
|
||||
t.Errorf("statusTests[%v] failed", num)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateInternalOrderID(t *testing.T) {
|
||||
id, err := uuid.NewV4()
|
||||
if err != nil {
|
||||
t.Errorf("unable to create uuid: %s", err)
|
||||
}
|
||||
od := Detail{
|
||||
InternalOrderID: id.String(),
|
||||
}
|
||||
od.GenerateInternalOrderID()
|
||||
if od.InternalOrderID != id.String() {
|
||||
t.Error("Should not be able to generate a new internal order ID")
|
||||
}
|
||||
|
||||
od = Detail{}
|
||||
od.GenerateInternalOrderID()
|
||||
if od.InternalOrderID == "" {
|
||||
t.Error("unable to generate internal order ID")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetail_Copy(t *testing.T) {
|
||||
d := []Detail{
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gofrs/uuid"
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/validate"
|
||||
@@ -208,6 +209,9 @@ func (d *Detail) UpdateOrderFromDetail(m *Detail) {
|
||||
if d.ID == "" {
|
||||
d.ID = m.ID
|
||||
}
|
||||
if d.InternalOrderID == "" {
|
||||
d.InternalOrderID = m.InternalOrderID
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateOrderFromModify Will update an order detail (used in order management)
|
||||
@@ -405,6 +409,40 @@ func (d *Detail) MatchFilter(f *Filter) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsActive returns true if an order has a status that indicates it is
|
||||
// currently available on the exchange
|
||||
func (d *Detail) IsActive() bool {
|
||||
if d.Amount <= 0 || d.Amount <= d.ExecutedAmount {
|
||||
return false
|
||||
}
|
||||
return d.Status == Active || d.Status == Open || d.Status == PartiallyFilled || d.Status == New ||
|
||||
d.Status == AnyStatus || d.Status == PendingCancel || d.Status == Hidden || d.Status == UnknownStatus ||
|
||||
d.Status == AutoDeleverage || d.Status == Pending
|
||||
}
|
||||
|
||||
// IsInactive returns true if an order has a status that indicates it is
|
||||
// currently not available on the exchange
|
||||
func (d *Detail) IsInactive() bool {
|
||||
if d.Amount <= 0 || d.Amount <= d.ExecutedAmount {
|
||||
return true
|
||||
}
|
||||
return d.Status == Filled || d.Status == Cancelled || d.Status == InsufficientBalance || d.Status == MarketUnavailable ||
|
||||
d.Status == Rejected || d.Status == PartiallyCancelled || d.Status == Expired || d.Status == Closed
|
||||
}
|
||||
|
||||
// GenerateInternalOrderID sets a new V4 order ID or a V5 order ID if
|
||||
// the V4 function returns an error
|
||||
func (d *Detail) GenerateInternalOrderID() {
|
||||
if d.InternalOrderID == "" {
|
||||
var id uuid.UUID
|
||||
id, err := uuid.NewV4()
|
||||
if err != nil {
|
||||
id = uuid.NewV5(uuid.UUID{}, d.ID)
|
||||
}
|
||||
d.InternalOrderID = id.String()
|
||||
}
|
||||
}
|
||||
|
||||
// Copy will return a copy of Detail
|
||||
func (d *Detail) Copy() Detail {
|
||||
c := *d
|
||||
|
||||
Reference in New Issue
Block a user