exchanges: Order types update (#1850)

* Added TimeInForce type and updated related files

* Linter issue fix and minor coinbasepro type update

* Bitrex consts update

* added unit test and minor changes in bittrex

* Unit tests update

* Fix minor linter issues

* Update TestStringToTimeInForce unit test

* fix conflict with gateio timeInForce

* Update order tests

* Complete updating the order unit tests

* update kucoin and deribit wrapper to match the time in force change

* fix time-in-force related test errors

* linter issue fix

* time in force constants, functions and unit tests update

* shift tif policies to TimeInForce

* Update time-in-force, related functions, and unit tests

* fix linter issue and time-in-force processing

* added a good till crossing tif value

* order type fix and fix related tim-in-force entries

* update time-in-force unmarshaling and unit test

* update order type to support time-in-force and hybrid order type representation

* added tests for type and time-in-force check from order type

* fix time-in-force error in gateio

* fix minor unit test issues

* linter issue fix

* update based on review comments

* add unit test and fix missing issues

* minor fix and added benchmark unit test

* change GTT to GTC for limit

* fix linter issue

* linter issues fix

* update order types declaration and handling by endpoints

* added time-in-force value to place order param

* fix minor issues based on review comment and move tif code to separate files

* update on exchanges linked to time-in-force

* resolve missing review comments

* minor linter issues fix

* added time-in-force handler and update timeInForce parametered endpoint

* minor fixes based on review

* nits fix

* update based on review

* linter fix

* rm getTimeInForce func and minor change to time-in-force

* minor change

* update based on review comments

* wrappers and time-in-force calling approach

* minor change

* update gateio string to timeInForce conversion and unit test

* fix types to string conversion

* fix build errors

* update on order types handling and unit tests

* fix linter issue

* order type unit tests update

* order types string as constant replacement and unit tests update

* update order type-string functions unit test
This commit is contained in:
Samuael A.
2025-06-12 08:39:17 +03:00
committed by GitHub
parent d5ba674fc4
commit a8a3bc4ee2
9 changed files with 265 additions and 148 deletions

View File

@@ -2226,7 +2226,7 @@ func TestGetActiveOrders(t *testing.T) {
Side: order.Buy,
}
getOrdersRequest.Type = order.OptimalLimitIOC
getOrdersRequest.Type = order.OptimalLimit
_, err = ku.GetActiveOrders(t.Context(), &getOrdersRequest)
require.ErrorIs(t, err, order.ErrUnsupportedOrderType)

View File

@@ -24,49 +24,64 @@ func orderTypeFromString(orderType string) (order.Type, order.TimeInForce, error
case orderIOC:
return order.Limit, order.ImmediateOrCancel, nil
case orderOptimalLimitIOC:
return order.OptimalLimitIOC, order.ImmediateOrCancel, nil
case "mmp":
return order.OptimalLimit, order.ImmediateOrCancel, nil
case orderMarketMakerProtection:
return order.MarketMakerProtection, order.UnknownTIF, nil
case "mmp_and_post_only":
return order.MarketMakerProtectionAndPostOnly, order.PostOnly, nil
case "twap":
case orderMarketMakerProtectionAndPostOnly:
return order.MarketMakerProtection, order.PostOnly, nil
case orderTWAP:
return order.TWAP, order.UnknownTIF, nil
case "move_order_stop":
case orderMoveOrderStop:
return order.TrailingStop, order.UnknownTIF, nil
case "chase":
case orderChase:
return order.Chase, order.UnknownTIF, nil
default:
return order.UnknownType, order.UnknownTIF, fmt.Errorf("%w %v", order.ErrTypeIsInvalid, orderType)
return order.UnknownType, order.UnknownTIF, fmt.Errorf("%w %q", order.ErrTypeIsInvalid, orderType)
}
}
// orderTypeString returns a string representation of order.Type instance
func orderTypeString(orderType order.Type, tif order.TimeInForce) (string, error) {
switch tif {
case order.PostOnly:
return orderPostOnly, nil
case order.FillOrKill:
return orderFOK, nil
case order.ImmediateOrCancel:
return orderIOC, nil
}
switch orderType {
case order.Market,
order.Limit,
order.Trigger,
order.OptimalLimitIOC,
order.MarketMakerProtection,
order.MarketMakerProtectionAndPostOnly,
case order.MarketMakerProtection:
if tif == order.PostOnly {
return orderMarketMakerProtectionAndPostOnly, nil
}
return orderMarketMakerProtection, nil
case order.OptimalLimit:
return orderOptimalLimitIOC, nil
case order.Limit:
if tif == order.PostOnly {
return orderPostOnly, nil
}
return orderLimit, nil
case order.Market:
switch tif {
case order.FillOrKill:
return orderFOK, nil
case order.ImmediateOrCancel:
return orderIOC, nil
}
return orderMarket, nil
case order.Trigger,
order.Chase,
order.TWAP,
order.OCO:
return orderType.Lower(), nil
case order.ConditionalStop:
return "conditional", nil
return orderConditional, nil
case order.TrailingStop:
return "move_order_stop", nil
return orderMoveOrderStop, nil
default:
return "", fmt.Errorf("%w: `%v`", order.ErrUnsupportedOrderType, orderType)
switch tif {
case order.PostOnly:
return orderPostOnly, nil
case order.FillOrKill:
return orderFOK, nil
case order.ImmediateOrCancel:
return orderIOC, nil
}
return "", fmt.Errorf("%w: %q", order.ErrUnsupportedOrderType, orderType)
}
}
@@ -152,15 +167,15 @@ func assetTypeFromInstrumentType(instrumentType string) (asset.Item, error) {
func assetTypeString(assetType asset.Item) (string, error) {
switch assetType {
case asset.Spot:
return "SPOT", nil
return instTypeSpot, nil
case asset.Margin:
return "MARGIN", nil
return instTypeMargin, nil
case asset.Futures:
return "FUTURES", nil
return instTypeFutures, nil
case asset.Options:
return "OPTION", nil
return instTypeOption, nil
case asset.PerpetualSwap:
return "SWAP", nil
return instTypeSwap, nil
default:
return "", asset.ErrNotSupported
}

View File

@@ -462,7 +462,7 @@ func (ok *Okx) PlaceTakeProfitStopLossOrder(ctx context.Context, arg *AlgoOrderP
if *arg == (AlgoOrderParams{}) {
return nil, common.ErrEmptyParams
}
if arg.OrderType != "conditional" {
if arg.OrderType != orderConditional {
return nil, fmt.Errorf("%w for TPSL: %q", order.ErrTypeIsInvalid, arg.OrderType)
}
if arg.StopLossTriggerPrice <= 0 {
@@ -481,7 +481,7 @@ func (ok *Okx) PlaceChaseAlgoOrder(ctx context.Context, arg *AlgoOrderParams) (*
if *arg == (AlgoOrderParams{}) {
return nil, common.ErrEmptyParams
}
if arg.OrderType != "chase" {
if arg.OrderType != orderChase {
return nil, fmt.Errorf("%w: order type value 'chase' is only supported for chase orders", order.ErrTypeIsInvalid)
}
if (arg.MaxChaseType == "" || arg.MaxChaseValue == 0) &&
@@ -496,7 +496,7 @@ func (ok *Okx) PlaceTriggerAlgoOrder(ctx context.Context, arg *AlgoOrderParams)
if *arg == (AlgoOrderParams{}) {
return nil, common.ErrEmptyParams
}
if arg.OrderType != "trigger" {
if arg.OrderType != orderTrigger {
return nil, fmt.Errorf("%w for Trigger: %q", order.ErrTypeIsInvalid, arg.OrderType)
}
if arg.TriggerPrice <= 0 {

View File

@@ -1222,7 +1222,7 @@ func TestPlaceChaseAlgoOrder(t *testing.T) {
_, err = ok.PlaceChaseAlgoOrder(contextGenerate(), arg)
require.ErrorIs(t, err, order.ErrTypeIsInvalid)
arg.OrderType = "chase"
arg.OrderType = orderChase
arg.MaxChaseType = "percentage"
_, err = ok.PlaceChaseAlgoOrder(contextGenerate(), arg)
require.ErrorIs(t, err, errPriceTrackingNotSet)
@@ -1250,7 +1250,7 @@ func TestPlaceChaseAlgoOrder(t *testing.T) {
AlgoClientOrderID: "681096944655273984",
InstrumentID: mainPair.String(),
LimitPrice: 100.22,
OrderType: "chase",
OrderType: orderChase,
TradeMode: "cross",
Side: order.Sell.Lower(),
MaxChaseType: "distance",
@@ -1297,14 +1297,14 @@ func TestPlaceTrailingStopOrder(t *testing.T) {
assert.ErrorIs(t, err, common.ErrEmptyParams)
_, err = ok.PlaceTrailingStopOrder(contextGenerate(), &AlgoOrderParams{Size: 2})
assert.ErrorIs(t, err, order.ErrTypeIsInvalid)
_, err = ok.PlaceTrailingStopOrder(contextGenerate(), &AlgoOrderParams{Size: 2, OrderType: "move_order_stop"})
_, err = ok.PlaceTrailingStopOrder(contextGenerate(), &AlgoOrderParams{Size: 2, OrderType: orderMoveOrderStop})
assert.ErrorIs(t, err, errPriceTrackingNotSet)
// Offline error handling unit tests for the base function PlaceAlgoOrder are already covered within unit test TestPlaceAlgoOrder.
sharedtestvalues.SkipTestIfCredentialsUnset(t, ok, canManipulateRealOrders)
result, err := ok.PlaceTrailingStopOrder(contextGenerate(), &AlgoOrderParams{
AlgoClientOrderID: "681096944655273984", CallbackRatio: 0.01,
InstrumentID: mainPair.String(), OrderType: "move_order_stop",
InstrumentID: mainPair.String(), OrderType: orderMoveOrderStop,
Side: order.Buy.Lower(), TradeMode: "isolated",
Size: 2, ActivePrice: 1234,
})
@@ -5843,26 +5843,35 @@ func TestOrderTypeString(t *testing.T) {
Expected string
Error error
}{
{OrderType: order.Market, TIF: order.UnknownTIF}: {Expected: orderMarket},
{OrderType: order.Limit, TIF: order.UnknownTIF}: {Expected: orderLimit},
{OrderType: order.Limit, TIF: order.PostOnly}: {Expected: orderPostOnly},
{OrderType: order.Limit, TIF: order.FillOrKill}: {Expected: orderFOK},
{OrderType: order.Limit, TIF: order.ImmediateOrCancel}: {Expected: orderIOC},
{OrderType: order.OptimalLimitIOC, TIF: order.UnknownTIF}: {Expected: orderOptimalLimitIOC},
{OrderType: order.MarketMakerProtection, TIF: order.UnknownTIF}: {Expected: "mmp"},
{OrderType: order.MarketMakerProtectionAndPostOnly, TIF: order.UnknownTIF}: {Expected: "mmp_and_post_only"},
{OrderType: order.Liquidation, TIF: order.UnknownTIF}: {Error: order.ErrUnsupportedOrderType},
{OrderType: order.OCO, TIF: order.UnknownTIF}: {Expected: "oco"},
{OrderType: order.TrailingStop, TIF: order.UnknownTIF}: {Expected: "move_order_stop"},
{OrderType: order.Chase, TIF: order.UnknownTIF}: {Expected: "chase"},
{OrderType: order.TWAP, TIF: order.UnknownTIF}: {Expected: "twap"},
{OrderType: order.ConditionalStop, TIF: order.UnknownTIF}: {Expected: "conditional"},
{OrderType: order.Trigger, TIF: order.UnknownTIF}: {Expected: "trigger"},
{OrderType: order.Market, TIF: order.UnknownTIF}: {Expected: orderMarket},
{OrderType: order.Limit, TIF: order.UnknownTIF}: {Expected: orderLimit},
{OrderType: order.Limit, TIF: order.PostOnly}: {Expected: orderPostOnly},
{OrderType: order.Market, TIF: order.FillOrKill}: {Expected: orderFOK},
{OrderType: order.Market, TIF: order.ImmediateOrCancel}: {Expected: orderIOC},
{OrderType: order.OptimalLimit, TIF: order.ImmediateOrCancel}: {Expected: orderOptimalLimitIOC},
{OrderType: order.MarketMakerProtection, TIF: order.UnknownTIF}: {Expected: orderMarketMakerProtection},
{OrderType: order.MarketMakerProtection, TIF: order.PostOnly}: {Expected: orderMarketMakerProtectionAndPostOnly},
{OrderType: order.Liquidation, TIF: order.UnknownTIF}: {Error: order.ErrUnsupportedOrderType},
{OrderType: order.OCO, TIF: order.UnknownTIF}: {Expected: orderOCO},
{OrderType: order.TrailingStop, TIF: order.UnknownTIF}: {Expected: orderMoveOrderStop},
{OrderType: order.Chase, TIF: order.UnknownTIF}: {Expected: orderChase},
{OrderType: order.TWAP, TIF: order.UnknownTIF}: {Expected: orderTWAP},
{OrderType: order.ConditionalStop, TIF: order.UnknownTIF}: {Expected: orderConditional},
{OrderType: order.Chase, TIF: order.GoodTillCancel}: {Expected: orderChase},
{OrderType: order.TWAP, TIF: order.ImmediateOrCancel}: {Expected: orderTWAP},
{OrderType: order.ConditionalStop, TIF: order.GoodTillDay}: {Expected: orderConditional},
{OrderType: order.Trigger, TIF: order.UnknownTIF}: {Expected: orderTrigger},
{OrderType: order.UnknownType, TIF: order.PostOnly}: {Expected: orderPostOnly},
{OrderType: order.UnknownType, TIF: order.FillOrKill}: {Expected: orderFOK},
{OrderType: order.UnknownType, TIF: order.ImmediateOrCancel}: {Expected: orderIOC},
}
for tc, val := range orderTypesToStringMap {
orderTypeString, err := orderTypeString(tc.OrderType, tc.TIF)
require.ErrorIs(t, err, val.Error)
assert.Equal(t, val.Expected, orderTypeString)
t.Run(tc.OrderType.String()+"/"+tc.TIF.String(), func(t *testing.T) {
t.Parallel()
orderTypeString, err := orderTypeString(tc.OrderType, tc.TIF)
require.ErrorIs(t, err, val.Error)
assert.Equal(t, val.Expected, orderTypeString)
})
}
}
@@ -6127,7 +6136,6 @@ func TestWsProcessSpreadTradesJSON(t *testing.T) {
func TestOrderTypeFromString(t *testing.T) {
t.Parallel()
orderTypeStrings := map[string]struct {
OType order.Type
TIF order.TimeInForce
@@ -6139,9 +6147,9 @@ func TestOrderTypeFromString(t *testing.T) {
"post_only": {OType: order.Limit, TIF: order.PostOnly},
"fok": {OType: order.Limit, TIF: order.FillOrKill},
"ioc": {OType: order.Limit, TIF: order.ImmediateOrCancel},
"optimal_limit_ioc": {OType: order.OptimalLimitIOC, TIF: order.ImmediateOrCancel},
"optimal_limit_ioc": {OType: order.OptimalLimit, TIF: order.ImmediateOrCancel},
"mmp": {OType: order.MarketMakerProtection},
"mmp_and_post_only": {OType: order.MarketMakerProtectionAndPostOnly, TIF: order.PostOnly},
"mmp_and_post_only": {OType: order.MarketMakerProtection, TIF: order.PostOnly},
"trigger": {OType: order.UnknownType, Error: order.ErrTypeIsInvalid},
"chase": {OType: order.Chase},
"move_order_stop": {OType: order.TrailingStop},
@@ -6149,10 +6157,13 @@ func TestOrderTypeFromString(t *testing.T) {
"abcd": {OType: order.UnknownType, Error: order.ErrTypeIsInvalid},
}
for s, exp := range orderTypeStrings {
oType, tif, err := orderTypeFromString(s)
require.ErrorIs(t, err, exp.Error)
assert.Equal(t, exp.OType, oType)
assert.Equal(t, exp.TIF.String(), tif.String(), s)
t.Run(s, func(t *testing.T) {
t.Parallel()
oType, tif, err := orderTypeFromString(s)
require.ErrorIs(t, err, exp.Error)
assert.Equal(t, exp.OType, oType)
assert.Equal(t, exp.TIF.String(), tif.String())
})
}
}

View File

@@ -41,19 +41,22 @@ const (
positionSideNet = "net"
)
// order types, margin balance types, and instrument types constants
const (
// orderLimit Limit order
orderLimit = "limit"
// orderMarket Market order
orderMarket = "market"
// orderPostOnly POST_ONLY order type
orderPostOnly = "post_only"
// orderFOK fill or kill order type
orderFOK = "fok"
// orderIOC IOC (immediate or cancel)
orderIOC = "ioc"
// orderOptimalLimitIOC OPTIMAL_LIMIT_IOC
orderOptimalLimitIOC = "optimal_limit_ioc"
orderLimit = "limit"
orderMarket = "market"
orderPostOnly = "post_only"
orderFOK = "fok"
orderIOC = "ioc"
orderOptimalLimitIOC = "optimal_limit_ioc"
orderConditional = "conditional"
orderMoveOrderStop = "move_order_stop"
orderChase = "chase"
orderTWAP = "twap"
orderTrigger = "trigger"
orderMarketMakerProtectionAndPostOnly = "mmp_and_post_only"
orderMarketMakerProtection = "mmp"
orderOCO = "oco"
// represents a margin balance type
marginBalanceReduce = "reduce"

View File

@@ -958,7 +958,7 @@ func (ok *Okx) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitR
return nil, err
}
return s.DeriveSubmitResponse(placeOrderResponse.OrderID)
case "trigger":
case orderTrigger:
result, err = ok.PlaceTriggerAlgoOrder(ctx, &AlgoOrderParams{
InstrumentID: pairString,
TradeMode: tradeMode,
@@ -970,7 +970,7 @@ func (ok *Okx) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitR
TriggerPrice: s.TriggerPrice,
TriggerPriceType: priceTypeString(s.TriggerPriceType),
})
case "conditional":
case orderConditional:
// Trigger Price and type are used as a stop losss trigger price and type.
result, err = ok.PlaceTakeProfitStopLossOrder(ctx, &AlgoOrderParams{
InstrumentID: pairString,
@@ -984,7 +984,7 @@ func (ok *Okx) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitR
StopLossOrderPrice: s.Price,
StopLossTriggerPriceType: priceTypeString(s.TriggerPriceType),
})
case "chase":
case orderChase:
if s.TrackingMode == order.UnknownTrackingMode {
return nil, fmt.Errorf("%w, tracking mode unset", order.ErrUnknownTrackingMode)
}
@@ -1002,7 +1002,7 @@ func (ok *Okx) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitR
MaxChaseType: s.TrackingMode.String(),
MaxChaseValue: s.TrackingValue,
})
case "move_order_stop":
case orderMoveOrderStop:
if s.TrackingMode == order.UnknownTrackingMode {
return nil, fmt.Errorf("%w, tracking mode unset", order.ErrUnknownTrackingMode)
}
@@ -1025,7 +1025,7 @@ func (ok *Okx) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitR
CallbackSpreadVariance: callbackSpread,
ActivePrice: s.TriggerPrice,
})
case "twap":
case orderTWAP:
if s.TrackingMode == order.UnknownTrackingMode {
return nil, fmt.Errorf("%w, tracking mode unset", order.ErrUnknownTrackingMode)
}
@@ -1050,7 +1050,7 @@ func (ok *Okx) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitR
LimitPrice: s.Price,
TimeInterval: kline.FifteenMin,
})
case "oco":
case orderOCO:
switch {
case s.RiskManagementModes.TakeProfit.Price <= 0:
return nil, fmt.Errorf("%w, take profit price is required", order.ErrPriceBelowMin)
@@ -1144,7 +1144,7 @@ func (ok *Okx) ModifyOrder(ctx context.Context, action *order.Modify) (*order.Mo
return nil, currency.ErrCurrencyPairEmpty
}
switch action.Type {
case order.UnknownType, order.Market, order.Limit, order.OptimalLimitIOC, order.MarketMakerProtection, order.MarketMakerProtectionAndPostOnly:
case order.UnknownType, order.Market, order.Limit, order.OptimalLimit, order.MarketMakerProtection:
amendRequest := AmendOrderRequestParams{
InstrumentID: pairFormat.Format(action.Pair),
NewQuantity: action.Amount,
@@ -1248,7 +1248,7 @@ func (ok *Okx) CancelOrder(ctx context.Context, ord *order.Cancel) error {
}
instrumentID := pairFormat.Format(ord.Pair)
switch ord.Type {
case order.UnknownType, order.Market, order.Limit, order.OptimalLimitIOC, order.MarketMakerProtection, order.MarketMakerProtectionAndPostOnly:
case order.UnknownType, order.Market, order.Limit, order.OptimalLimit, order.MarketMakerProtection:
req := CancelOrderRequestParam{
InstrumentID: instrumentID,
OrderID: ord.OrderID,
@@ -1301,7 +1301,7 @@ func (ok *Okx) CancelBatchOrders(ctx context.Context, o []order.Cancel) (*order.
return nil, currency.ErrCurrencyPairsEmpty
}
switch ord.Type {
case order.UnknownType, order.Market, order.Limit, order.OptimalLimitIOC, order.MarketMakerProtection, order.MarketMakerProtectionAndPostOnly:
case order.UnknownType, order.Market, order.Limit, order.OptimalLimit, order.MarketMakerProtection:
if o[x].ClientID == "" && o[x].OrderID == "" {
return nil, fmt.Errorf("%w, order ID required for order of type %v", order.ErrOrderIDNotSet, o[x].Type)
}

View File

@@ -297,6 +297,33 @@ func TestTitle(t *testing.T) {
require.Equal(t, "Limit", orderType.Title())
}
func TestOrderIs(t *testing.T) {
t.Parallel()
orderComparisonList := []struct {
Type Type
Targets []Type
}{
{Type: Limit | TakeProfit, Targets: []Type{TakeProfit, Limit}},
{Type: IOS, Targets: []Type{IOS}},
{Type: Stop, Targets: []Type{Stop}},
{Type: AnyType, Targets: []Type{AnyType}},
{Type: StopLimit, Targets: []Type{Stop, Limit}},
{Type: TakeProfit, Targets: []Type{TakeProfit}},
{Type: StopMarket, Targets: []Type{Stop, Market}},
{Type: TrailingStop, Targets: []Type{TrailingStop}},
{Type: UnknownType | Limit, Targets: []Type{Limit}},
{Type: TakeProfitMarket, Targets: []Type{TakeProfit, Market}},
}
for _, oType := range orderComparisonList {
t.Run(oType.Type.String(), func(t *testing.T) {
t.Parallel()
for _, target := range oType.Targets {
assert.Truef(t, oType.Type.Is(target), "expected %v, got %q", target, oType.Type.String())
}
})
}
}
func TestOrderTypes(t *testing.T) {
t.Parallel()
var orderType Type
@@ -305,6 +332,41 @@ func TestOrderTypes(t *testing.T) {
assert.Equal(t, "Unknown", orderType.Title())
}
func TestOrderTypeToString(t *testing.T) {
t.Parallel()
orderToToStringsList := []struct {
OrderType Type
String string
}{
{StopMarket, "STOP MARKET"},
{StopLimit, "STOP LIMIT"},
{Limit, "LIMIT"},
{Market, "MARKET"},
{Stop, "STOP"},
{ConditionalStop, "CONDITIONAL"},
{TWAP, "TWAP"},
{Chase, "CHASE"},
{TakeProfit, "TAKE PROFIT"},
{TakeProfitMarket, "TAKE PROFIT MARKET"},
{TrailingStop, "TRAILING_STOP"},
{IOS, "IOS"},
{Liquidation, "LIQUIDATION"},
{Trigger, "TRIGGER"},
{OCO, "OCO"},
{OptimalLimit, "OPTIMAL_LIMIT"},
{MarketMakerProtection, "MMP"},
{AnyType, "ANY"},
{UnknownType | Limit, "LIMIT"},
{StopMarket | ConditionalStop, "UNKNOWN"},
}
for _, tt := range orderToToStringsList {
t.Run(tt.String, func(t *testing.T) {
t.Parallel()
assert.Equal(t, tt.String, tt.OrderType.String())
})
}
}
func TestInferCostsAndTimes(t *testing.T) {
t.Parallel()
var detail Detail
@@ -736,6 +798,7 @@ func BenchmarkStringToOrderSide(b *testing.B) {
}
func TestStringToOrderType(t *testing.T) {
t.Parallel()
cases := []struct {
in string
out Type
@@ -766,14 +829,12 @@ func TestStringToOrderType(t *testing.T) {
{"conDitiOnal", ConditionalStop, nil},
{"oCo", OCO, nil},
{"mMp", MarketMakerProtection, nil},
{"Mmp_And_Post_oNly", MarketMakerProtectionAndPostOnly, nil},
{"tWaP", TWAP, nil},
{"TWAP", TWAP, nil},
{"woahMan", UnknownType, errUnrecognisedOrderType},
{"chase", Chase, nil},
{"MOVE_ORDER_STOP", TrailingStop, nil},
{"mOVe_OrdeR_StoP", TrailingStop, nil},
{"optimal_limit_IoC", OptimalLimitIOC, nil},
{"Stop_market", StopMarket, nil},
{"liquidation", Liquidation, nil},
{"LiQuidation", Liquidation, nil},
@@ -781,10 +842,13 @@ func TestStringToOrderType(t *testing.T) {
{"Take ProfIt", TakeProfit, nil},
{"TAKE PROFIT MARkEt", TakeProfitMarket, nil},
{"TAKE_PROFIT_MARkEt", TakeProfitMarket, nil},
{"optimal_limit", OptimalLimit, nil},
{"OPTIMAL_LIMIT", OptimalLimit, nil},
}
for i := range cases {
testData := &cases[i]
t.Run(testData.in, func(t *testing.T) {
t.Parallel()
out, err := StringToOrderType(testData.in)
require.ErrorIs(t, err, testData.err)
assert.Equal(t, testData.out, out)

View File

@@ -348,7 +348,12 @@ const (
)
// Type enforces a standard for order types across the code base
type Type uint32
type Type uint64
// Is checks to see if the Type contains the Type cmp
func (t Type) Is(cmp Type) bool {
return cmp != 0 && t&cmp == cmp
}
// Defined package order types
const (
@@ -356,22 +361,45 @@ const (
Limit Type = 1 << iota
Market
Stop
StopLimit
StopMarket
TakeProfit
TakeProfitMarket
TrailingStop
IOS
AnyType
Liquidation
Trigger
OptimalLimitIOC
OCO // One-cancels-the-other order
ConditionalStop // One-way stop order
MarketMakerProtection // market-maker-protection used with portfolio margin mode. See https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-place-order
MarketMakerProtectionAndPostOnly // market-maker-protection and post-only mode. Used in Okx exchange orders.
TWAP // time-weighted average price.
Chase // chase order. See https://www.okx.com/docs-v5/en/#order-book-trading-algo-trading-post-place-algo-order
OCO // One-cancels-the-other order
ConditionalStop // One-way stop order
TWAP // time-weighted average price
Chase // chase limit order
OptimalLimit
MarketMakerProtection
// Hybrid order types
StopLimit = Stop | Limit
StopMarket = Stop | Market
TakeProfitMarket = TakeProfit | Market
)
// order-type string representations
const (
orderStopMarket = "STOP MARKET"
orderStopLimit = "STOP LIMIT"
orderLimit = "LIMIT"
orderMarket = "MARKET"
orderStop = "STOP"
orderConditionalStop = "CONDITIONAL"
orderTWAP = "TWAP"
orderChase = "CHASE"
orderTakeProfit = "TAKE PROFIT"
orderTakeProfitMarket = "TAKE PROFIT MARKET"
orderTrailingStop = "TRAILING_STOP"
orderIOS = "IOS"
orderLiquidation = "LIQUIDATION"
orderTrigger = "TRIGGER"
orderOCO = "OCO"
orderOptimalLimit = "OPTIMAL_LIMIT"
orderMarketMakerProtection = "MMP"
orderAnyType = "ANY"
)
// Side enforces a standard for order sides across the code base

View File

@@ -667,44 +667,42 @@ func (d *Detail) DeriveCancel() (*Cancel, error) {
// String implements the stringer interface
func (t Type) String() string {
switch t {
case AnyType:
return "ANY"
case Limit:
return "LIMIT"
case Market:
return "MARKET"
case Stop:
return "STOP"
case ConditionalStop:
return "CONDITIONAL"
case MarketMakerProtection:
return "MMP"
case MarketMakerProtectionAndPostOnly:
return "MMP_AND_POST_ONLY"
case TWAP:
return "TWAP"
case Chase:
return "CHASE"
case StopLimit:
return "STOP LIMIT"
case StopMarket:
return "STOP MARKET"
return orderStopMarket
case StopLimit:
return orderStopLimit
case Limit:
return orderLimit
case Market:
return orderMarket
case Stop:
return orderStop
case ConditionalStop:
return orderConditionalStop
case TWAP:
return orderTWAP
case Chase:
return orderChase
case TakeProfit:
return "TAKE PROFIT"
return orderTakeProfit
case TakeProfitMarket:
return "TAKE PROFIT MARKET"
return orderTakeProfitMarket
case TrailingStop:
return "TRAILING_STOP"
return orderTrailingStop
case IOS:
return "IOS"
return orderIOS
case Liquidation:
return "LIQUIDATION"
return orderLiquidation
case Trigger:
return "TRIGGER"
case OptimalLimitIOC:
return "OPTIMAL_LIMIT_IOC"
return orderTrigger
case OCO:
return "OCO"
return orderOCO
case OptimalLimit:
return orderOptimalLimit
case MarketMakerProtection:
return orderMarketMakerProtection
case AnyType:
return orderAnyType
default:
return "UNKNOWN"
}
@@ -1102,43 +1100,41 @@ func (s Side) MarshalJSON() ([]byte, error) {
func StringToOrderType(oType string) (Type, error) {
oType = strings.ToUpper(oType)
switch oType {
case Limit.String(), "EXCHANGE LIMIT":
case orderLimit, "EXCHANGE LIMIT":
return Limit, nil
case Market.String(), "EXCHANGE MARKET":
case orderMarket, "EXCHANGE MARKET":
return Market, nil
case Stop.String(), "STOP LOSS", "STOP_LOSS", "EXCHANGE STOP":
case orderStop, "STOP LOSS", "STOP_LOSS", "EXCHANGE STOP":
return Stop, nil
case StopLimit.String(), "EXCHANGE STOP LIMIT", "STOP_LIMIT":
case orderStopLimit, "EXCHANGE STOP LIMIT", "STOP_LIMIT":
return StopLimit, nil
case StopMarket.String(), "STOP_MARKET":
case orderStopMarket, "STOP_MARKET":
return StopMarket, nil
case TrailingStop.String(), "TRAILING STOP", "EXCHANGE TRAILING STOP", "MOVE_ORDER_STOP":
case orderTrailingStop, "TRAILING STOP", "EXCHANGE TRAILING STOP", "MOVE_ORDER_STOP":
return TrailingStop, nil
case IOS.String():
case orderIOS:
return IOS, nil
case AnyType.String():
case orderAnyType:
return AnyType, nil
case Trigger.String():
case orderTrigger:
return Trigger, nil
case OptimalLimitIOC.String():
return OptimalLimitIOC, nil
case OCO.String():
case orderOptimalLimit:
return OptimalLimit, nil
case orderOCO:
return OCO, nil
case ConditionalStop.String():
case orderConditionalStop:
return ConditionalStop, nil
case MarketMakerProtection.String():
case orderMarketMakerProtection:
return MarketMakerProtection, nil
case MarketMakerProtectionAndPostOnly.String():
return MarketMakerProtectionAndPostOnly, nil
case TWAP.String():
case orderTWAP:
return TWAP, nil
case Chase.String():
case orderChase:
return Chase, nil
case TakeProfitMarket.String(), "TAKE_PROFIT_MARKET":
case orderTakeProfitMarket, "TAKE_PROFIT_MARKET":
return TakeProfitMarket, nil
case TakeProfit.String(), "TAKE_PROFIT":
case orderTakeProfit, "TAKE_PROFIT":
return TakeProfit, nil
case Liquidation.String():
case orderLiquidation:
return Liquidation, nil
default:
return UnknownType, fmt.Errorf("'%v' %w", oType, errUnrecognisedOrderType)