mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-06-01 15:10:44 +00:00
Engine improvements
This commit is contained in:
165
engine/orders.go
165
engine/orders.go
@@ -2,10 +2,12 @@ package engine
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
"github.com/thrasher-/gocryptotrader/communications/base"
|
||||
exchange "github.com/thrasher-/gocryptotrader/exchanges"
|
||||
log "github.com/thrasher-/gocryptotrader/logger"
|
||||
)
|
||||
@@ -16,9 +18,10 @@ var (
|
||||
ErrOrdersAlreadyExists = errors.New("order already exists")
|
||||
)
|
||||
|
||||
type orderStore struct {
|
||||
m sync.Mutex
|
||||
Orders map[string][]exchange.OrderDetail
|
||||
func (o *orderStore) Get() map[string][]exchange.OrderDetail {
|
||||
o.m.Lock()
|
||||
defer o.m.Unlock()
|
||||
return o.Orders
|
||||
}
|
||||
|
||||
func (o *orderStore) exists(order *exchange.OrderDetail) bool {
|
||||
@@ -50,13 +53,6 @@ func (o *orderStore) Add(order *exchange.OrderDetail) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type orderManager struct {
|
||||
started int32
|
||||
stopped int32
|
||||
shutdown chan struct{}
|
||||
orderStore orderStore
|
||||
}
|
||||
|
||||
func (o *orderManager) Started() bool {
|
||||
return atomic.LoadInt32(&o.started) == 1
|
||||
}
|
||||
@@ -67,6 +63,9 @@ func (o *orderManager) Start() error {
|
||||
}
|
||||
|
||||
log.Debugln("Order manager starting...")
|
||||
|
||||
// test param
|
||||
o.cfg.CancelOrdersOnShutdown = true
|
||||
o.shutdown = make(chan struct{})
|
||||
o.orderStore.Orders = make(map[string][]exchange.OrderDetail)
|
||||
go o.run()
|
||||
@@ -82,17 +81,59 @@ func (o *orderManager) Stop() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *orderManager) gracefulShutdown() {
|
||||
if o.cfg.CancelOrdersOnShutdown {
|
||||
log.Debug("Order manager: Cancelling any open orders...")
|
||||
orders := o.orderStore.Get()
|
||||
if orders == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for k, v := range orders {
|
||||
log.Debugf("Order manager: Cancelling order(s) for exchange %s.", k)
|
||||
for y := range v {
|
||||
log.Debugf("order manager: Cancelling order ID %v [%v]",
|
||||
v[y].ID, v[y])
|
||||
err := o.Cancel(k, &exchange.OrderCancellation{
|
||||
OrderID: v[y].ID,
|
||||
})
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Order manager: Exchange %s unable to cancel order ID=%v. Err: %s",
|
||||
k, v[y].ID, err)
|
||||
log.Debugln(msg)
|
||||
Bot.CommsRelayer.PushEvent(base.Event{
|
||||
Type: "order",
|
||||
Message: msg,
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf("Order manager: Exchange %s order ID=%v cancelled.",
|
||||
k, v[y].ID)
|
||||
log.Debugln(msg)
|
||||
Bot.CommsRelayer.PushEvent(base.Event{
|
||||
Type: "order",
|
||||
Message: msg,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (o *orderManager) run() {
|
||||
log.Debugln("Order manager started.")
|
||||
tick := time.NewTicker(OrderManagerDelay)
|
||||
Bot.ServicesWG.Add(1)
|
||||
defer func() {
|
||||
log.Debugf("Order manager shutdown.")
|
||||
tick.Stop()
|
||||
Bot.ServicesWG.Done()
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-o.shutdown:
|
||||
o.gracefulShutdown()
|
||||
return
|
||||
case <-tick.C:
|
||||
o.processOrders()
|
||||
@@ -100,9 +141,99 @@ func (o *orderManager) run() {
|
||||
}
|
||||
}
|
||||
|
||||
func (o *orderManager) Cancel() {}
|
||||
func (o *orderManager) CancelAllOrders() {}
|
||||
|
||||
func (o *orderManager) Place() {}
|
||||
func (o *orderManager) Cancel(exchName string, order *exchange.OrderCancellation) error {
|
||||
if exchName == "" {
|
||||
return errors.New("order exchange name is empty")
|
||||
}
|
||||
|
||||
if order == nil {
|
||||
return errors.New("order cancel param is nil")
|
||||
}
|
||||
|
||||
if order.OrderID == "" {
|
||||
return errors.New("order id is empty")
|
||||
}
|
||||
|
||||
exch := GetExchangeByName(exchName)
|
||||
if exch == nil {
|
||||
return errors.New("unable to get exchange by name")
|
||||
}
|
||||
|
||||
if order.AssetType.String() != "" && !exch.GetAssetTypes().Contains(order.AssetType) {
|
||||
return errors.New("order asset type not supported by exchange")
|
||||
}
|
||||
|
||||
return exch.CancelOrder(order)
|
||||
}
|
||||
|
||||
func (o *orderManager) Submit(exchName string, order *exchange.OrderSubmission) (*orderSubmitResponse, error) {
|
||||
if exchName == "" {
|
||||
return nil, errors.New("order exchange name must be specified")
|
||||
}
|
||||
|
||||
if order == nil {
|
||||
return nil, exchange.ErrOrderSubmissionIsNil
|
||||
}
|
||||
|
||||
if err := order.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if o.cfg.EnforceLimitConfig {
|
||||
if !o.cfg.AllowMarketOrders && order.OrderType == exchange.MarketOrderType {
|
||||
return nil, errors.New("order market type is not allowed")
|
||||
}
|
||||
|
||||
if o.cfg.LimitAmount > 0 && order.Amount > o.cfg.LimitAmount {
|
||||
return nil, errors.New("order limit exceeds allowed limit")
|
||||
}
|
||||
|
||||
if len(o.cfg.AllowedExchanges) > 0 &&
|
||||
!common.StringDataCompareInsensitive(o.cfg.AllowedExchanges, exchName) {
|
||||
return nil, errors.New("order exchange not found in allowed list")
|
||||
}
|
||||
|
||||
if len(o.cfg.AllowedPairs) > 0 && !o.cfg.AllowedPairs.Contains(order.Pair, true) {
|
||||
return nil, errors.New("order pair not found in allowed list")
|
||||
}
|
||||
}
|
||||
|
||||
exch := GetExchangeByName(exchName)
|
||||
if exch == nil {
|
||||
return nil, errors.New("unable to get exchange by name")
|
||||
}
|
||||
|
||||
id, err := common.GetV4UUID()
|
||||
if err != nil {
|
||||
log.Warnf("Order manager: Unable to generate UUID. Err: %s", err)
|
||||
}
|
||||
|
||||
result, err := exch.SubmitOrder(order)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result.IsOrderPlaced {
|
||||
return nil, errors.New("order unable to be placed")
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf("Order manager: Exchange %s submitted order ID=%v [Ours: %v] pair=%v price=%v amount=%v side=%v type=%v.",
|
||||
exchName, result.OrderID, id.String(), order.Pair, order.Price, order.Amount, order.OrderSide, order.OrderType)
|
||||
log.Debugln(msg)
|
||||
Bot.CommsRelayer.PushEvent(base.Event{
|
||||
Type: "order",
|
||||
Message: msg,
|
||||
})
|
||||
|
||||
return &orderSubmitResponse{
|
||||
SubmitOrderResponse: exchange.SubmitOrderResponse{
|
||||
OrderID: result.OrderID,
|
||||
},
|
||||
OurOrderID: id.String(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (o *orderManager) processOrders() {
|
||||
authExchanges := GetAuthAPISupportedExchanges()
|
||||
@@ -123,8 +254,14 @@ func (o *orderManager) processOrders() {
|
||||
order := &result[x]
|
||||
result := o.orderStore.Add(order)
|
||||
if result != ErrOrdersAlreadyExists {
|
||||
log.Debugf("Order manager: Exchange %s added order ID=%v pair=%v price=%v amount=%v side=%v type=%v.",
|
||||
msg := fmt.Sprintf("Order manager: Exchange %s added order ID=%v pair=%v price=%v amount=%v side=%v type=%v.",
|
||||
order.Exchange, order.ID, order.CurrencyPair, order.Price, order.Amount, order.OrderSide, order.OrderType)
|
||||
log.Debug(msg)
|
||||
Bot.CommsRelayer.PushEvent(base.Event{
|
||||
Type: "order",
|
||||
Message: msg,
|
||||
})
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user