mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-23 15:10:15 +00:00
orders: Add derive modify struct method from order.Detail (#948)
* orders: Add derive modify struct method to order.Detail and then subsequent method to derive and standardize response details * exchanges: call modify method in wrappers * linter: fixes * engine/wsroutineman: remove print summary * glorious: nits, removed modifyOrder functionality for Bithumb. There are not docs to support this. * Update exchanges/order/orders.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * glorious: nits Co-authored-by: Scott <gloriousCode@users.noreply.github.com>
This commit is contained in:
@@ -843,7 +843,6 @@ func BenchmarkStringToOrderStatus(b *testing.B) {
|
||||
}
|
||||
|
||||
func TestUpdateOrderFromModify(t *testing.T) {
|
||||
var leet = "1337"
|
||||
od := Detail{ID: "1"}
|
||||
updated := time.Now()
|
||||
|
||||
@@ -852,94 +851,50 @@ func TestUpdateOrderFromModify(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
om := Modify{
|
||||
om := ModifyResponse{
|
||||
ImmediateOrCancel: true,
|
||||
HiddenOrder: true,
|
||||
FillOrKill: true,
|
||||
PostOnly: true,
|
||||
Leverage: 1.0,
|
||||
Price: 1,
|
||||
Amount: 1,
|
||||
LimitPriceUpper: 1,
|
||||
LimitPriceLower: 1,
|
||||
TriggerPrice: 1,
|
||||
QuoteAmount: 1,
|
||||
ExecutedAmount: 1,
|
||||
RemainingAmount: 1,
|
||||
Fee: 1,
|
||||
Exchange: "1",
|
||||
InternalOrderID: "1",
|
||||
ID: "1",
|
||||
AccountID: "1",
|
||||
ClientID: "1",
|
||||
WalletAddress: "1",
|
||||
Type: 1,
|
||||
Side: 1,
|
||||
Status: 1,
|
||||
AssetType: 1,
|
||||
LastUpdated: updated,
|
||||
Pair: pair,
|
||||
Trades: []TradeHistory{},
|
||||
}
|
||||
|
||||
od.UpdateOrderFromModify(&om)
|
||||
od.UpdateOrderFromModifyResponse(&om)
|
||||
if od.InternalOrderID == "1" {
|
||||
t.Error("Should not be able to update the internal order ID")
|
||||
}
|
||||
if !od.ImmediateOrCancel {
|
||||
t.Error("Failed to update")
|
||||
}
|
||||
if !od.HiddenOrder {
|
||||
t.Error("Failed to update")
|
||||
}
|
||||
if !od.FillOrKill {
|
||||
t.Error("Failed to update")
|
||||
}
|
||||
if !od.PostOnly {
|
||||
t.Error("Failed to update")
|
||||
}
|
||||
if od.Leverage != 1 {
|
||||
t.Error("Failed to update")
|
||||
}
|
||||
if od.Price != 1 {
|
||||
t.Error("Failed to update")
|
||||
}
|
||||
if od.Amount != 1 {
|
||||
t.Error("Failed to update")
|
||||
}
|
||||
if od.LimitPriceLower != 1 {
|
||||
t.Error("Failed to update")
|
||||
}
|
||||
if od.LimitPriceUpper != 1 {
|
||||
t.Error("Failed to update")
|
||||
}
|
||||
if od.TriggerPrice != 1 {
|
||||
t.Error("Failed to update")
|
||||
}
|
||||
if od.QuoteAmount != 1 {
|
||||
t.Error("Failed to update")
|
||||
}
|
||||
if od.ExecutedAmount != 1 {
|
||||
t.Error("Failed to update")
|
||||
}
|
||||
if od.RemainingAmount != 1 {
|
||||
t.Error("Failed to update")
|
||||
}
|
||||
if od.Fee != 1 {
|
||||
t.Error("Failed to update")
|
||||
}
|
||||
if od.Exchange != "" {
|
||||
t.Error("Should not be able to update exchange via modify")
|
||||
}
|
||||
if od.ID != "1" {
|
||||
t.Error("Failed to update")
|
||||
}
|
||||
if od.ClientID != "1" {
|
||||
t.Error("Failed to update")
|
||||
}
|
||||
if od.WalletAddress != "1" {
|
||||
t.Error("Failed to update")
|
||||
}
|
||||
if od.Type != 1 {
|
||||
t.Error("Failed to update")
|
||||
}
|
||||
@@ -961,49 +916,6 @@ func TestUpdateOrderFromModify(t *testing.T) {
|
||||
if od.Trades != nil {
|
||||
t.Error("Failed to update")
|
||||
}
|
||||
|
||||
om.Trades = append(om.Trades, TradeHistory{TID: "1"}, TradeHistory{TID: "2"})
|
||||
od.UpdateOrderFromModify(&om)
|
||||
if len(od.Trades) != 2 {
|
||||
t.Error("Failed to add trades")
|
||||
}
|
||||
om.Trades[0].Exchange = leet
|
||||
om.Trades[0].Price = 1337
|
||||
om.Trades[0].Fee = 1337
|
||||
om.Trades[0].IsMaker = true
|
||||
om.Trades[0].Timestamp = updated
|
||||
om.Trades[0].Description = leet
|
||||
om.Trades[0].Side = UnknownSide
|
||||
om.Trades[0].Type = UnknownType
|
||||
om.Trades[0].Amount = 1337
|
||||
od.UpdateOrderFromModify(&om)
|
||||
if od.Trades[0].Exchange == leet {
|
||||
t.Error("Should not be able to update exchange from update")
|
||||
}
|
||||
if od.Trades[0].Price != 1337 {
|
||||
t.Error("Failed to update trades")
|
||||
}
|
||||
if od.Trades[0].Fee != 1337 {
|
||||
t.Error("Failed to update trades")
|
||||
}
|
||||
if !od.Trades[0].IsMaker {
|
||||
t.Error("Failed to update trades")
|
||||
}
|
||||
if od.Trades[0].Timestamp != updated {
|
||||
t.Error("Failed to update trades")
|
||||
}
|
||||
if od.Trades[0].Description != leet {
|
||||
t.Error("Failed to update trades")
|
||||
}
|
||||
if od.Trades[0].Side != UnknownSide {
|
||||
t.Error("Failed to update trades")
|
||||
}
|
||||
if od.Trades[0].Type != UnknownType {
|
||||
t.Error("Failed to update trades")
|
||||
}
|
||||
if od.Trades[0].Amount != 1337 {
|
||||
t.Error("Failed to update trades")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateOrderFromDetail(t *testing.T) {
|
||||
@@ -1635,6 +1547,84 @@ func TestDetail_CopyPointerOrderSlice(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeriveModify(t *testing.T) {
|
||||
t.Parallel()
|
||||
var o *Detail
|
||||
if _, err := o.DeriveModify(); !errors.Is(err, errOrderDetailIsNil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errOrderDetailIsNil)
|
||||
}
|
||||
|
||||
pair := currency.NewPair(currency.BTC, currency.AUD)
|
||||
|
||||
o = &Detail{
|
||||
Exchange: "wow",
|
||||
ID: "wow2",
|
||||
ClientOrderID: "wow3",
|
||||
Type: Market,
|
||||
Side: Long,
|
||||
AssetType: asset.Futures,
|
||||
Pair: pair,
|
||||
}
|
||||
|
||||
mod, err := o.DeriveModify()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
|
||||
if mod == nil {
|
||||
t.Fatal("should not be nil")
|
||||
}
|
||||
|
||||
if mod.Exchange != "wow" ||
|
||||
mod.ID != "wow2" ||
|
||||
mod.ClientOrderID != "wow3" ||
|
||||
mod.Type != Market ||
|
||||
mod.Side != Long ||
|
||||
mod.AssetType != asset.Futures ||
|
||||
!mod.Pair.Equal(pair) {
|
||||
t.Fatal("unexpected values")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeriveModifyResponse(t *testing.T) {
|
||||
t.Parallel()
|
||||
var mod *Modify
|
||||
if _, err := mod.DeriveModifyResponse(); !errors.Is(err, errOrderDetailIsNil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errOrderDetailIsNil)
|
||||
}
|
||||
|
||||
pair := currency.NewPair(currency.BTC, currency.AUD)
|
||||
|
||||
mod = &Modify{
|
||||
Exchange: "wow",
|
||||
ID: "wow2",
|
||||
ClientOrderID: "wow3",
|
||||
Type: Market,
|
||||
Side: Long,
|
||||
AssetType: asset.Futures,
|
||||
Pair: pair,
|
||||
}
|
||||
|
||||
modresp, err := mod.DeriveModifyResponse()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
|
||||
if modresp == nil {
|
||||
t.Fatal("should not be nil")
|
||||
}
|
||||
|
||||
if modresp.Exchange != "wow" ||
|
||||
modresp.OrderID != "wow2" ||
|
||||
modresp.ClientOrderID != "wow3" ||
|
||||
modresp.Type != Market ||
|
||||
modresp.Side != Long ||
|
||||
modresp.AssetType != asset.Futures ||
|
||||
!modresp.Pair.Equal(pair) {
|
||||
t.Fatal("unexpected values")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeriveCancel(t *testing.T) {
|
||||
t.Parallel()
|
||||
var o *Detail
|
||||
@@ -1660,7 +1650,6 @@ func TestDeriveCancel(t *testing.T) {
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
|
||||
if cancel.Exchange != "wow" ||
|
||||
cancel.ID != "wow1" ||
|
||||
cancel.AccountID != "wow2" ||
|
||||
@@ -1671,6 +1660,6 @@ func TestDeriveCancel(t *testing.T) {
|
||||
cancel.Side != Long ||
|
||||
!cancel.Pair.Equal(pair) ||
|
||||
cancel.AssetType != asset.Futures {
|
||||
t.Fatal("unexpected values")
|
||||
t.Fatalf("unexpected values %+v", cancel)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,40 +83,47 @@ type SubmitResponse struct {
|
||||
// Each exchange has their own requirements, so not all fields
|
||||
// are required to be populated
|
||||
type Modify struct {
|
||||
// Order Identifiers
|
||||
Exchange string
|
||||
ID string
|
||||
ClientOrderID string
|
||||
Type Type
|
||||
Side Side
|
||||
AssetType asset.Item
|
||||
Pair currency.Pair
|
||||
|
||||
// Change fields
|
||||
ImmediateOrCancel bool
|
||||
HiddenOrder bool
|
||||
FillOrKill bool
|
||||
PostOnly bool
|
||||
Leverage float64
|
||||
Price float64
|
||||
Amount float64
|
||||
LimitPriceUpper float64
|
||||
LimitPriceLower float64
|
||||
TriggerPrice float64
|
||||
QuoteAmount float64
|
||||
ExecutedAmount float64
|
||||
RemainingAmount float64
|
||||
Fee float64
|
||||
Exchange string
|
||||
InternalOrderID string
|
||||
ID string
|
||||
ClientOrderID string
|
||||
AccountID string
|
||||
ClientID string
|
||||
WalletAddress string
|
||||
Type Type
|
||||
Side Side
|
||||
Status Status
|
||||
AssetType asset.Item
|
||||
Date time.Time
|
||||
LastUpdated time.Time
|
||||
Pair currency.Pair
|
||||
Trades []TradeHistory
|
||||
}
|
||||
|
||||
// ModifyResponse is an order modifying return type
|
||||
type ModifyResponse struct {
|
||||
OrderID string
|
||||
// Order Identifiers
|
||||
Exchange string
|
||||
OrderID string
|
||||
ClientOrderID string
|
||||
Pair currency.Pair
|
||||
Type Type
|
||||
Side Side
|
||||
Status Status
|
||||
AssetType asset.Item
|
||||
|
||||
// Fields that will be copied over from Modify
|
||||
ImmediateOrCancel bool
|
||||
PostOnly bool
|
||||
Price float64
|
||||
Amount float64
|
||||
TriggerPrice float64
|
||||
|
||||
// Fields that need to be handled in scope after DeriveModifyResponse()
|
||||
// if applicable
|
||||
RemainingAmount float64
|
||||
Date time.Time
|
||||
LastUpdated time.Time
|
||||
}
|
||||
|
||||
// Detail contains all properties of an order
|
||||
|
||||
@@ -242,26 +242,18 @@ func (d *Detail) UpdateOrderFromDetail(m *Detail) {
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateOrderFromModify Will update an order detail (used in order management)
|
||||
// UpdateOrderFromModifyResponse Will update an order detail (used in order management)
|
||||
// by comparing passed in and existing values
|
||||
func (d *Detail) UpdateOrderFromModify(m *Modify) {
|
||||
func (d *Detail) UpdateOrderFromModifyResponse(m *ModifyResponse) {
|
||||
var updated bool
|
||||
if m.ID != "" && d.ID != m.ID {
|
||||
d.ID = m.ID
|
||||
if m.OrderID != "" && d.ID != m.OrderID {
|
||||
d.ID = m.OrderID
|
||||
updated = true
|
||||
}
|
||||
if d.ImmediateOrCancel != m.ImmediateOrCancel {
|
||||
d.ImmediateOrCancel = m.ImmediateOrCancel
|
||||
updated = true
|
||||
}
|
||||
if d.HiddenOrder != m.HiddenOrder {
|
||||
d.HiddenOrder = m.HiddenOrder
|
||||
updated = true
|
||||
}
|
||||
if d.FillOrKill != m.FillOrKill {
|
||||
d.FillOrKill = m.FillOrKill
|
||||
updated = true
|
||||
}
|
||||
if m.Price > 0 && m.Price != d.Price {
|
||||
d.Price = m.Price
|
||||
updated = true
|
||||
@@ -270,34 +262,10 @@ func (d *Detail) UpdateOrderFromModify(m *Modify) {
|
||||
d.Amount = m.Amount
|
||||
updated = true
|
||||
}
|
||||
if m.LimitPriceUpper > 0 && m.LimitPriceUpper != d.LimitPriceUpper {
|
||||
d.LimitPriceUpper = m.LimitPriceUpper
|
||||
updated = true
|
||||
}
|
||||
if m.LimitPriceLower > 0 && m.LimitPriceLower != d.LimitPriceLower {
|
||||
d.LimitPriceLower = m.LimitPriceLower
|
||||
updated = true
|
||||
}
|
||||
if m.TriggerPrice > 0 && m.TriggerPrice != d.TriggerPrice {
|
||||
d.TriggerPrice = m.TriggerPrice
|
||||
updated = true
|
||||
}
|
||||
if m.QuoteAmount > 0 && m.QuoteAmount != d.QuoteAmount {
|
||||
d.QuoteAmount = m.QuoteAmount
|
||||
updated = true
|
||||
}
|
||||
if m.ExecutedAmount > 0 && m.ExecutedAmount != d.ExecutedAmount {
|
||||
d.ExecutedAmount = m.ExecutedAmount
|
||||
updated = true
|
||||
}
|
||||
if m.Fee > 0 && m.Fee != d.Fee {
|
||||
d.Fee = m.Fee
|
||||
updated = true
|
||||
}
|
||||
if m.AccountID != "" && m.AccountID != d.AccountID {
|
||||
d.AccountID = m.AccountID
|
||||
updated = true
|
||||
}
|
||||
if m.PostOnly != d.PostOnly {
|
||||
d.PostOnly = m.PostOnly
|
||||
updated = true
|
||||
@@ -308,18 +276,6 @@ func (d *Detail) UpdateOrderFromModify(m *Modify) {
|
||||
d.Pair = m.Pair
|
||||
updated = true
|
||||
}
|
||||
if m.Leverage != 0 && m.Leverage != d.Leverage {
|
||||
d.Leverage = m.Leverage
|
||||
updated = true
|
||||
}
|
||||
if m.ClientID != "" && m.ClientID != d.ClientID {
|
||||
d.ClientID = m.ClientID
|
||||
updated = true
|
||||
}
|
||||
if m.WalletAddress != "" && m.WalletAddress != d.WalletAddress {
|
||||
d.WalletAddress = m.WalletAddress
|
||||
updated = true
|
||||
}
|
||||
if m.Type != UnknownType && m.Type != d.Type {
|
||||
d.Type = m.Type
|
||||
updated = true
|
||||
@@ -336,52 +292,6 @@ func (d *Detail) UpdateOrderFromModify(m *Modify) {
|
||||
d.AssetType = m.AssetType
|
||||
updated = true
|
||||
}
|
||||
for x := range m.Trades {
|
||||
var found bool
|
||||
for y := range d.Trades {
|
||||
if d.Trades[y].TID != m.Trades[x].TID {
|
||||
continue
|
||||
}
|
||||
found = true
|
||||
if d.Trades[y].Fee != m.Trades[x].Fee {
|
||||
d.Trades[y].Fee = m.Trades[x].Fee
|
||||
updated = true
|
||||
}
|
||||
if m.Trades[x].Price != 0 && d.Trades[y].Price != m.Trades[x].Price {
|
||||
d.Trades[y].Price = m.Trades[x].Price
|
||||
updated = true
|
||||
}
|
||||
if d.Trades[y].Side != m.Trades[x].Side {
|
||||
d.Trades[y].Side = m.Trades[x].Side
|
||||
updated = true
|
||||
}
|
||||
if d.Trades[y].Type != m.Trades[x].Type {
|
||||
d.Trades[y].Type = m.Trades[x].Type
|
||||
updated = true
|
||||
}
|
||||
if d.Trades[y].Description != m.Trades[x].Description {
|
||||
d.Trades[y].Description = m.Trades[x].Description
|
||||
updated = true
|
||||
}
|
||||
if m.Trades[x].Amount != 0 && d.Trades[y].Amount != m.Trades[x].Amount {
|
||||
d.Trades[y].Amount = m.Trades[x].Amount
|
||||
updated = true
|
||||
}
|
||||
if d.Trades[y].Timestamp != m.Trades[x].Timestamp {
|
||||
d.Trades[y].Timestamp = m.Trades[x].Timestamp
|
||||
updated = true
|
||||
}
|
||||
if d.Trades[y].IsMaker != m.Trades[x].IsMaker {
|
||||
d.Trades[y].IsMaker = m.Trades[x].IsMaker
|
||||
updated = true
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
d.Trades = append(d.Trades, m.Trades[x])
|
||||
updated = true
|
||||
}
|
||||
m.RemainingAmount -= m.Trades[x].Amount
|
||||
}
|
||||
if m.RemainingAmount > 0 && m.RemainingAmount != d.RemainingAmount {
|
||||
d.RemainingAmount = m.RemainingAmount
|
||||
updated = true
|
||||
@@ -494,6 +404,47 @@ func CopyPointerOrderSlice(old []*Detail) []*Detail {
|
||||
return copySlice
|
||||
}
|
||||
|
||||
// DeriveModify populates a modify struct by the managed order details. Note:
|
||||
// Price, Amount, Trigger price and order execution bools need to be changed
|
||||
// in scope. This only derives identifiers for ease.
|
||||
func (d *Detail) DeriveModify() (*Modify, error) {
|
||||
if d == nil {
|
||||
return nil, errOrderDetailIsNil
|
||||
}
|
||||
return &Modify{
|
||||
Exchange: d.Exchange,
|
||||
ID: d.ID,
|
||||
ClientOrderID: d.ClientOrderID,
|
||||
Type: d.Type,
|
||||
Side: d.Side,
|
||||
AssetType: d.AssetType,
|
||||
Pair: d.Pair,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeriveModifyResponse populates a modify response with its identifiers for
|
||||
// cross exchange standard. NOTE: New OrderID and/or ClientOrderID plus any
|
||||
// changes *might* need to be populated in scope.
|
||||
func (m *Modify) DeriveModifyResponse() (*ModifyResponse, error) {
|
||||
if m == nil {
|
||||
return nil, errOrderDetailIsNil
|
||||
}
|
||||
return &ModifyResponse{
|
||||
Exchange: m.Exchange,
|
||||
OrderID: m.ID,
|
||||
ClientOrderID: m.ClientOrderID,
|
||||
Type: m.Type,
|
||||
Side: m.Side,
|
||||
AssetType: m.AssetType,
|
||||
Pair: m.Pair,
|
||||
ImmediateOrCancel: m.ImmediateOrCancel,
|
||||
PostOnly: m.PostOnly,
|
||||
Price: m.Price,
|
||||
Amount: m.Amount,
|
||||
TriggerPrice: m.TriggerPrice,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeriveCancel populates a cancel struct by the managed order details
|
||||
func (d *Detail) DeriveCancel() (*Cancel, error) {
|
||||
if d == nil {
|
||||
|
||||
Reference in New Issue
Block a user