mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 23:16:45 +00:00
protocol/order: adds additional fields for trading requirements (#1552)
* Add in initial handling for quote/base currency deployment requirements * include client order ID checking * glorious: suggestions * spell and fix * linter/context/test * rework tests and order side specific requirements * linter * mend panic at the disco * mending more panics at the disco * anudda fix brudda * glorious: NITTTTTT BOOOOOMB * leftover things and stuff * whoops * tie in gateio * glorious: nit fixes life and everything. * thrasher: nits --------- Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io>
This commit is contained in:
@@ -274,7 +274,7 @@ func (a *Alphapoint) GetHistoricTrades(_ context.Context, _ currency.Pair, _ ass
|
||||
// SubmitOrder submits a new order and returns a true value when
|
||||
// successfully submitted
|
||||
func (a *Alphapoint) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitResponse, error) {
|
||||
if err := s.Validate(); err != nil {
|
||||
if err := s.Validate(a.GetTradingRequirements()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -882,7 +882,7 @@ func (b *Binance) GetHistoricTrades(ctx context.Context, p currency.Pair, a asse
|
||||
|
||||
// SubmitOrder submits a new order
|
||||
func (b *Binance) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitResponse, error) {
|
||||
if err := s.Validate(); err != nil {
|
||||
if err := s.Validate(b.GetTradingRequirements()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var orderID string
|
||||
|
||||
@@ -530,7 +530,7 @@ func (bi *Binanceus) SubmitOrder(ctx context.Context, s *order.Submit) (*order.S
|
||||
var submitOrderResponse order.SubmitResponse
|
||||
var timeInForce RequestParamsTimeForceType
|
||||
var sideType string
|
||||
err := s.Validate()
|
||||
err := s.Validate(bi.GetTradingRequirements())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -608,7 +608,7 @@ allTrades:
|
||||
|
||||
// SubmitOrder submits a new order
|
||||
func (b *Bitfinex) SubmitOrder(ctx context.Context, o *order.Submit) (*order.SubmitResponse, error) {
|
||||
if err := o.Validate(); err != nil {
|
||||
if err := o.Validate(b.GetTradingRequirements()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -450,7 +450,7 @@ func (b *Bithumb) GetHistoricTrades(_ context.Context, _ currency.Pair, _ asset.
|
||||
// SubmitOrder submits a new order
|
||||
// TODO: Fill this out to support limit orders
|
||||
func (b *Bithumb) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitResponse, error) {
|
||||
if err := s.Validate(); err != nil {
|
||||
if err := s.Validate(b.GetTradingRequirements()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -693,7 +693,7 @@ allTrades:
|
||||
|
||||
// SubmitOrder submits a new order
|
||||
func (b *Bitmex) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitResponse, error) {
|
||||
if err := s.Validate(); err != nil {
|
||||
if err := s.Validate(b.GetTradingRequirements()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -491,7 +491,7 @@ func (b *Bitstamp) GetHistoricTrades(_ context.Context, _ currency.Pair, _ asset
|
||||
|
||||
// SubmitOrder submits a new order
|
||||
func (b *Bitstamp) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitResponse, error) {
|
||||
if err := s.Validate(); err != nil {
|
||||
if err := s.Validate(b.GetTradingRequirements()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -464,7 +464,7 @@ func (b *BTCMarkets) GetHistoricTrades(_ context.Context, _ currency.Pair, _ ass
|
||||
|
||||
// SubmitOrder submits a new order
|
||||
func (b *BTCMarkets) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitResponse, error) {
|
||||
if err := s.Validate(); err != nil {
|
||||
if err := s.Validate(b.GetTradingRequirements()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -496,7 +496,7 @@ func (b *BTSE) GetHistoricTrades(_ context.Context, _ currency.Pair, _ asset.Ite
|
||||
|
||||
// SubmitOrder submits a new order
|
||||
func (b *BTSE) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitResponse, error) {
|
||||
if err := s.Validate(); err != nil {
|
||||
if err := s.Validate(b.GetTradingRequirements()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -778,7 +778,7 @@ func orderTypeToString(oType order.Type) string {
|
||||
|
||||
// SubmitOrder submits a new order
|
||||
func (by *Bybit) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitResponse, error) {
|
||||
err := s.Validate()
|
||||
err := s.Validate(by.GetTradingRequirements())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -440,7 +440,7 @@ func (c *CoinbasePro) GetHistoricTrades(_ context.Context, _ currency.Pair, _ as
|
||||
|
||||
// SubmitOrder submits a new order
|
||||
func (c *CoinbasePro) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitResponse, error) {
|
||||
if err := s.Validate(); err != nil {
|
||||
if err := s.Validate(c.GetTradingRequirements()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -494,7 +494,7 @@ func (c *COINUT) GetHistoricTrades(_ context.Context, _ currency.Pair, _ asset.I
|
||||
|
||||
// SubmitOrder submits a new order
|
||||
func (c *COINUT) SubmitOrder(ctx context.Context, o *order.Submit) (*order.SubmitResponse, error) {
|
||||
err := o.Validate()
|
||||
err := o.Validate(c.GetTradingRequirements())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -632,7 +632,7 @@ func (d *Deribit) GetHistoricTrades(ctx context.Context, p currency.Pair, assetT
|
||||
|
||||
// SubmitOrder submits a new order
|
||||
func (d *Deribit) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitResponse, error) {
|
||||
err := s.Validate()
|
||||
err := s.Validate(d.GetTradingRequirements())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1942,3 +1942,11 @@ func GetDefaultConfig(ctx context.Context, exch IBotExchange) (*config.Exchange,
|
||||
func (b *Base) GetCurrencyTradeURL(context.Context, asset.Item, currency.Pair) (string, error) {
|
||||
return "", common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// GetTradingRequirements returns the exchange's trading requirements.
|
||||
func (b *Base) GetTradingRequirements() protocol.TradingRequirements {
|
||||
if b == nil {
|
||||
return protocol.TradingRequirements{}
|
||||
}
|
||||
return b.Features.TradingRequirements
|
||||
}
|
||||
|
||||
@@ -3062,3 +3062,11 @@ func TestGetCurrencyTradeURL(t *testing.T) {
|
||||
_, err := b.GetCurrencyTradeURL(context.Background(), asset.Spot, currency.NewPair(currency.BTC, currency.USDT))
|
||||
require.ErrorIs(t, err, common.ErrFunctionNotSupported)
|
||||
}
|
||||
|
||||
func TestGetTradingRequirements(t *testing.T) {
|
||||
t.Parallel()
|
||||
requirements := (*Base)(nil).GetTradingRequirements()
|
||||
require.Empty(t, requirements)
|
||||
requirements = (&Base{Features: Features{TradingRequirements: protocol.TradingRequirements{ClientOrderID: true}}}).GetTradingRequirements()
|
||||
require.NotEmpty(t, requirements)
|
||||
}
|
||||
|
||||
@@ -150,9 +150,10 @@ type WithdrawalHistory struct {
|
||||
// Features stores the supported and enabled features
|
||||
// for the exchange
|
||||
type Features struct {
|
||||
Supports FeaturesSupported
|
||||
Enabled FeaturesEnabled
|
||||
Subscriptions subscription.List
|
||||
Supports FeaturesSupported
|
||||
Enabled FeaturesEnabled
|
||||
Subscriptions subscription.List
|
||||
TradingRequirements protocol.TradingRequirements
|
||||
}
|
||||
|
||||
// FeaturesEnabled stores the exchange enabled features
|
||||
|
||||
@@ -472,7 +472,7 @@ func (e *EXMO) GetHistoricTrades(_ context.Context, _ currency.Pair, _ asset.Ite
|
||||
|
||||
// SubmitOrder submits a new order
|
||||
func (e *EXMO) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitResponse, error) {
|
||||
if err := s.Validate(); err != nil {
|
||||
if err := s.Validate(e.GetTradingRequirements()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,10 @@ func (g *Gateio) SetDefaults() {
|
||||
}
|
||||
|
||||
g.Features = exchange.Features{
|
||||
TradingRequirements: protocol.TradingRequirements{
|
||||
SpotMarketOrderAmountPurchaseQuotationOnly: true,
|
||||
SpotMarketOrderAmountSellBaseOnly: true,
|
||||
},
|
||||
Supports: exchange.FeaturesSupported{
|
||||
REST: true,
|
||||
Websocket: true,
|
||||
@@ -984,7 +988,7 @@ func (g *Gateio) GetHistoricTrades(_ context.Context, _ currency.Pair, _ asset.I
|
||||
// SubmitOrder submits a new order
|
||||
// TODO: support multiple order types (IOC)
|
||||
func (g *Gateio) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitResponse, error) {
|
||||
err := s.Validate()
|
||||
err := s.Validate(g.GetTradingRequirements())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1008,11 +1012,20 @@ func (g *Gateio) SubmitOrder(ctx context.Context, s *order.Submit) (*order.Submi
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// When doing spot market orders when purchasing base currency, the
|
||||
// quote currency amount is used. When selling the base currency the
|
||||
// base currency amount is used.
|
||||
tradingAmount := s.Amount
|
||||
if tradingAmount == 0 && s.Type == order.Market {
|
||||
tradingAmount = s.QuoteAmount
|
||||
}
|
||||
|
||||
sOrder, err := g.PlaceSpotOrder(ctx, &CreateOrderRequestData{
|
||||
Side: s.Side.Lower(),
|
||||
Type: s.Type.Lower(),
|
||||
Account: g.assetTypeToString(s.AssetType),
|
||||
Amount: types.Number(s.Amount),
|
||||
Amount: types.Number(tradingAmount),
|
||||
Price: types.Number(s.Price),
|
||||
CurrencyPair: s.Pair,
|
||||
Text: s.ClientOrderID,
|
||||
|
||||
@@ -498,7 +498,7 @@ allTrades:
|
||||
|
||||
// SubmitOrder submits a new order
|
||||
func (g *Gemini) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitResponse, error) {
|
||||
if err := s.Validate(); err != nil {
|
||||
if err := s.Validate(g.GetTradingRequirements()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -460,7 +460,7 @@ allTrades:
|
||||
|
||||
// SubmitOrder submits a new order
|
||||
func (h *HitBTC) SubmitOrder(ctx context.Context, o *order.Submit) (*order.SubmitResponse, error) {
|
||||
err := o.Validate()
|
||||
err := o.Validate(h.GetTradingRequirements())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -993,7 +993,7 @@ func (h *HUOBI) GetHistoricTrades(_ context.Context, _ currency.Pair, _ asset.It
|
||||
|
||||
// SubmitOrder submits a new order
|
||||
func (h *HUOBI) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitResponse, error) {
|
||||
if err := s.Validate(); err != nil {
|
||||
if err := s.Validate(h.GetTradingRequirements()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/margin"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/protocol"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/stream"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/subscription"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
|
||||
@@ -34,8 +35,12 @@ type IBotExchange interface {
|
||||
Shutdown() error
|
||||
GetName() string
|
||||
SetEnabled(bool)
|
||||
|
||||
GetEnabledFeatures() FeaturesEnabled
|
||||
GetSupportedFeatures() FeaturesSupported
|
||||
// GetTradingRequirements returns trading requirements for the exchange
|
||||
GetTradingRequirements() protocol.TradingRequirements
|
||||
|
||||
FetchTicker(ctx context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error)
|
||||
UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error)
|
||||
UpdateTickers(ctx context.Context, a asset.Item) error
|
||||
|
||||
@@ -716,7 +716,7 @@ func (k *Kraken) GetHistoricTrades(_ context.Context, _ currency.Pair, _ asset.I
|
||||
|
||||
// SubmitOrder submits a new order
|
||||
func (k *Kraken) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitResponse, error) {
|
||||
err := s.Validate()
|
||||
err := s.Validate(k.GetTradingRequirements())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -66,6 +66,9 @@ func (ku *Kucoin) SetDefaults() {
|
||||
log.Errorln(log.ExchangeSys, err)
|
||||
}
|
||||
ku.Features = exchange.Features{
|
||||
TradingRequirements: protocol.TradingRequirements{
|
||||
ClientOrderID: true,
|
||||
},
|
||||
Supports: exchange.FeaturesSupported{
|
||||
REST: true,
|
||||
Websocket: true,
|
||||
@@ -673,7 +676,7 @@ func (ku *Kucoin) GetHistoricTrades(_ context.Context, _ currency.Pair, _ asset.
|
||||
|
||||
// SubmitOrder submits a new order
|
||||
func (ku *Kucoin) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitResponse, error) {
|
||||
err := s.Validate()
|
||||
err := s.Validate(ku.GetTradingRequirements())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -441,7 +441,7 @@ allTrades:
|
||||
|
||||
// SubmitOrder submits a new order
|
||||
func (l *Lbank) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitResponse, error) {
|
||||
if err := s.Validate(); err != nil {
|
||||
if err := s.Validate(l.GetTradingRequirements()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -577,7 +577,7 @@ func (o *Okcoin) SubmitOrder(ctx context.Context, s *order.Submit) (*order.Submi
|
||||
if !o.SupportsAsset(s.AssetType) {
|
||||
return nil, fmt.Errorf("%w, asset: %v", asset.ErrNotSupported, s.AssetType)
|
||||
}
|
||||
err := s.Validate()
|
||||
err := s.Validate(o.GetTradingRequirements())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -712,7 +712,7 @@ allTrades:
|
||||
|
||||
// SubmitOrder submits a new order
|
||||
func (ok *Okx) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitResponse, error) {
|
||||
if err := s.Validate(); err != nil {
|
||||
if err := s.Validate(ok.GetTradingRequirements()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !ok.SupportsAsset(s.AssetType) {
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/protocol"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/validate"
|
||||
)
|
||||
|
||||
@@ -24,9 +25,12 @@ func TestSubmit_Validate(t *testing.T) {
|
||||
t.Parallel()
|
||||
testPair := currency.NewPair(currency.BTC, currency.LTC)
|
||||
tester := []struct {
|
||||
ExpectedErr error
|
||||
Submit *Submit
|
||||
ValidOpts validate.Checker
|
||||
ExpectedErr error
|
||||
Submit *Submit
|
||||
ValidOpts validate.Checker
|
||||
HasToPurchaseWithQuoteAmountSet bool
|
||||
HasToSellWithBaseAmountSet bool
|
||||
RequiresID bool
|
||||
}{
|
||||
{
|
||||
ExpectedErr: ErrSubmissionIsNil,
|
||||
@@ -178,13 +182,72 @@ func TestSubmit_Validate(t *testing.T) {
|
||||
},
|
||||
ValidOpts: validate.Check(func() error { return nil }),
|
||||
}, // valid order!
|
||||
{
|
||||
ExpectedErr: ErrAmountMustBeSet,
|
||||
Submit: &Submit{
|
||||
Exchange: "test",
|
||||
Pair: testPair,
|
||||
Side: Buy,
|
||||
Type: Market,
|
||||
Amount: 1,
|
||||
AssetType: asset.Spot,
|
||||
},
|
||||
HasToPurchaseWithQuoteAmountSet: true,
|
||||
ValidOpts: validate.Check(func() error { return nil }),
|
||||
},
|
||||
{
|
||||
ExpectedErr: ErrAmountMustBeSet,
|
||||
Submit: &Submit{
|
||||
Exchange: "test",
|
||||
Pair: testPair,
|
||||
Side: Sell,
|
||||
Type: Market,
|
||||
QuoteAmount: 1,
|
||||
AssetType: asset.Spot,
|
||||
},
|
||||
HasToSellWithBaseAmountSet: true,
|
||||
ValidOpts: validate.Check(func() error { return nil }),
|
||||
},
|
||||
{
|
||||
ExpectedErr: ErrClientOrderIDMustBeSet,
|
||||
Submit: &Submit{
|
||||
Exchange: "test",
|
||||
Pair: testPair,
|
||||
Side: Buy,
|
||||
Type: Market,
|
||||
Amount: 1,
|
||||
AssetType: asset.Spot,
|
||||
},
|
||||
RequiresID: true,
|
||||
ValidOpts: validate.Check(func() error { return nil }),
|
||||
},
|
||||
{
|
||||
ExpectedErr: nil,
|
||||
Submit: &Submit{
|
||||
Exchange: "test",
|
||||
Pair: testPair,
|
||||
Side: Buy,
|
||||
Type: Market,
|
||||
Amount: 1,
|
||||
AssetType: asset.Spot,
|
||||
ClientOrderID: "69420",
|
||||
},
|
||||
RequiresID: true,
|
||||
ValidOpts: validate.Check(func() error { return nil }),
|
||||
},
|
||||
}
|
||||
|
||||
for x := range tester {
|
||||
err := tester[x].Submit.Validate(tester[x].ValidOpts)
|
||||
if !errors.Is(err, tester[x].ExpectedErr) {
|
||||
t.Fatalf("Unexpected result. %d Got: %v, want: %v", x+1, err, tester[x].ExpectedErr)
|
||||
}
|
||||
for x, tc := range tester {
|
||||
t.Run(strconv.Itoa(x), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
requirements := protocol.TradingRequirements{
|
||||
SpotMarketOrderAmountPurchaseQuotationOnly: tc.HasToPurchaseWithQuoteAmountSet,
|
||||
SpotMarketOrderAmountSellBaseOnly: tc.HasToSellWithBaseAmountSet,
|
||||
ClientOrderID: tc.RequiresID,
|
||||
}
|
||||
err := tc.Submit.Validate(requirements, tc.ValidOpts)
|
||||
assert.ErrorIs(t, err, tc.ExpectedErr)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/protocol"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/validate"
|
||||
"github.com/thrasher-corp/gocryptotrader/log"
|
||||
"golang.org/x/text/cases"
|
||||
@@ -30,16 +31,17 @@ const (
|
||||
notPlaced = InsufficientBalance | MarketUnavailable | Rejected
|
||||
)
|
||||
|
||||
// Public error vars for order package
|
||||
var (
|
||||
// ErrUnableToPlaceOrder defines an error when an order submission has
|
||||
// failed.
|
||||
ErrUnableToPlaceOrder = errors.New("order not placed")
|
||||
// ErrOrderNotFound is returned when no order is found
|
||||
ErrOrderNotFound = errors.New("order not found")
|
||||
|
||||
// ErrUnknownPriceType returned when price type is unknown
|
||||
ErrUnknownPriceType = errors.New("unknown price type")
|
||||
ErrUnableToPlaceOrder = errors.New("order not placed")
|
||||
ErrOrderNotFound = errors.New("order not found")
|
||||
ErrUnknownPriceType = errors.New("unknown price type")
|
||||
ErrAmountMustBeSet = errors.New("amount must be set")
|
||||
ErrClientOrderIDMustBeSet = errors.New("client order ID must be set")
|
||||
ErrUnknownSubmissionAmountType = errors.New("unknown submission amount type")
|
||||
)
|
||||
|
||||
var (
|
||||
errTimeInForceConflict = errors.New("multiple time in force options applied")
|
||||
errUnrecognisedOrderType = errors.New("unrecognised order type")
|
||||
errUnrecognisedOrderStatus = errors.New("unrecognised order status")
|
||||
@@ -56,7 +58,7 @@ func IsValidOrderSubmissionSide(s Side) bool {
|
||||
}
|
||||
|
||||
// Validate checks the supplied data and returns whether it's valid
|
||||
func (s *Submit) Validate(opt ...validate.Checker) error {
|
||||
func (s *Submit) Validate(requirements protocol.TradingRequirements, opt ...validate.Checker) error {
|
||||
if s == nil {
|
||||
return ErrSubmissionIsNil
|
||||
}
|
||||
@@ -105,6 +107,18 @@ func (s *Submit) Validate(opt ...validate.Checker) error {
|
||||
return ErrPriceMustBeSetIfLimitOrder
|
||||
}
|
||||
|
||||
if requirements.ClientOrderID && s.ClientOrderID == "" {
|
||||
return fmt.Errorf("submit validation error %w, client order ID must be set to satisfy submission requirements", ErrClientOrderIDMustBeSet)
|
||||
}
|
||||
|
||||
if requirements.SpotMarketOrderAmountPurchaseQuotationOnly && s.QuoteAmount == 0 && s.Type == Market && s.AssetType == asset.Spot && s.Side.IsLong() {
|
||||
return fmt.Errorf("submit validation error %w, quote amount to be sold must be set to 'QuoteAmount' field to satisfy trading requirements", ErrAmountMustBeSet)
|
||||
}
|
||||
|
||||
if requirements.SpotMarketOrderAmountSellBaseOnly && s.Amount == 0 && s.Type == Market && s.AssetType == asset.Spot && s.Side.IsShort() {
|
||||
return fmt.Errorf("submit validation error %w, base amount being sold must be set to 'Amount' field to satisfy trading requirements", ErrAmountMustBeSet)
|
||||
}
|
||||
|
||||
for _, o := range opt {
|
||||
err := o.Check()
|
||||
if err != nil {
|
||||
|
||||
@@ -541,7 +541,7 @@ allTrades:
|
||||
|
||||
// SubmitOrder submits a new order
|
||||
func (p *Poloniex) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitResponse, error) {
|
||||
if err := s.Validate(); err != nil {
|
||||
if err := s.Validate(p.GetTradingRequirements()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -50,3 +50,22 @@ type Features struct {
|
||||
// types instead of just being denoted as spot holdings.
|
||||
HasAssetTypeAccountSegregation bool `json:"hasAssetTypeAccountSegregation,omitempty"`
|
||||
}
|
||||
|
||||
// TradingRequirements defines the requirements for trading on the exchange.
|
||||
type TradingRequirements struct {
|
||||
// SpotMarketOrderAmountPurchaseQuotationOnly requires the amount to be in
|
||||
// quote currency or what is to be sold for when you purchase base currency.
|
||||
// For example, long BTC-USD, the quotation amount is USD.
|
||||
// NOTE: Due to an exchange's matching engine process, the base amount
|
||||
// acquired may vary from what is intended due to price fluctuations and
|
||||
// liquidity on the books. Care must be taken when implementing a market
|
||||
// neutral strategy.
|
||||
SpotMarketOrderAmountPurchaseQuotationOnly bool
|
||||
// SpotMarketOrderAmountSellBaseOnly requires the amount to be in the
|
||||
// base currency or what is intended to be purchased. For example, short
|
||||
// BTC-USD, the base amount is BTC.
|
||||
SpotMarketOrderAmountSellBaseOnly bool
|
||||
// ClientOrderID is a unique identifier for the order that is generated by
|
||||
// the client and is required for order submission.
|
||||
ClientOrderID bool
|
||||
}
|
||||
|
||||
@@ -370,7 +370,7 @@ func (y *Yobit) GetHistoricTrades(_ context.Context, _ currency.Pair, _ asset.It
|
||||
// SubmitOrder submits a new order
|
||||
// Yobit only supports limit orders
|
||||
func (y *Yobit) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitResponse, error) {
|
||||
if err := s.Validate(); err != nil {
|
||||
if err := s.Validate(y.GetTradingRequirements()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user