OKX: Support exchange order limits (#1186)

* OKX: Support exchange order limits

Adds support for PriceStepIncrementSize and MinAmount limits

* OKX: Test UpdateOrderExecutionLimits on all assets

* OKX: Added asset types for order limit tests
This commit is contained in:
Gareth Kirwan
2023-05-09 01:59:09 +01:00
committed by GitHub
parent 970f65ba72
commit 6e1cbfc31e
2 changed files with 147 additions and 48 deletions

View File

@@ -1847,6 +1847,63 @@ func TestUpdateTradablePairs(t *testing.T) {
}
}
func TestUpdateOrderExecutionLimits(t *testing.T) {
t.Parallel()
type limitTest struct {
pair currency.Pair
step float64
min float64
}
tests := map[asset.Item][]limitTest{
asset.Spot: {
{currency.NewPair(currency.ETH, currency.USDT), 0.01, 0.0001},
{currency.NewPair(currency.BTC, currency.USDT), 0.1, 0.00001},
},
asset.Margin: {
{currency.NewPair(currency.ETH, currency.USDT), 0.01, 0.0001},
{currency.NewPair(currency.ETH, currency.BTC), 0.00001, 0.0001},
},
}
for _, a := range []asset.Item{asset.PerpetualSwap, asset.Futures, asset.Options} {
pairs, err := ok.FetchTradablePairs(context.Background(), a)
if err != nil {
t.Errorf("Error fetching dated %s pairs for test: %v", a, err)
}
stepIncr := 0.1
if a == asset.Options {
stepIncr = 0.0005
}
tests[a] = []limitTest{{pairs[0], stepIncr, 1}}
}
for _, a := range ok.GetAssetTypes(false) {
if err := ok.UpdateOrderExecutionLimits(context.Background(), a); err != nil {
t.Error("Okx UpdateOrderExecutionLimits() error", err)
continue
}
for _, tt := range tests[a] {
limits, err := ok.GetOrderExecutionLimits(a, tt.pair)
if err != nil {
t.Errorf("Okx GetOrderExecutionLimits() error during TestUpdateOrderExecutionLimits; Asset: %s Pair: %s Err: %v", a, tt.pair, err)
continue
}
if got := limits.PriceStepIncrementSize; got != tt.step {
t.Errorf("Okx UpdateOrderExecutionLimits wrong PriceStepIncrementSize; Asset: %s Pair: %s Expected: %v Got: %v", a, tt.pair, tt.step, got)
}
if got := limits.MinAmount; got != tt.min {
t.Errorf("Okx UpdateOrderExecutionLimits wrong MinAmount; Pair: %s Expected: %v Got: %v", tt.pair, tt.min, got)
}
}
}
}
func TestUpdateTicker(t *testing.T) {
t.Parallel()
if _, err := ok.UpdateTicker(context.Background(), currency.NewPair(currency.BTC, currency.USDT), asset.Spot); err != nil {

View File

@@ -262,15 +262,23 @@ func (ok *Okx) Run(ctx context.Context) {
ok.PrintEnabledPairs()
}
if !ok.GetEnabledFeatures().AutoPairUpdates {
return
assetTypes := ok.GetAssetTypes(false)
for i := range assetTypes {
if err := ok.UpdateOrderExecutionLimits(ctx, assetTypes[i]); err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to set exchange order execution limits. Err: %v",
ok.Name,
err)
}
}
err := ok.UpdateTradablePairs(ctx, false)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update tradable pairs. Err: %s",
ok.Name,
err)
if ok.GetEnabledFeatures().AutoPairUpdates {
if err := ok.UpdateTradablePairs(ctx, false); err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update tradable pairs. Err: %s",
ok.Name,
err)
}
}
}
@@ -281,46 +289,7 @@ func (ok *Okx) GetServerTime(ctx context.Context, _ asset.Item) (time.Time, erro
// FetchTradablePairs returns a list of the exchanges tradable pairs
func (ok *Okx) FetchTradablePairs(ctx context.Context, a asset.Item) (currency.Pairs, error) {
if !ok.SupportsAsset(a) {
return nil, fmt.Errorf("asset type of %s is not supported by %s", a, ok.Name)
}
var insts []Instrument
var err error
switch a {
case asset.Spot:
insts, err = ok.GetInstruments(ctx, &InstrumentsFetchParams{
InstrumentType: okxInstTypeSpot,
})
case asset.Futures:
insts, err = ok.GetInstruments(ctx, &InstrumentsFetchParams{
InstrumentType: okxInstTypeFutures,
})
case asset.PerpetualSwap:
insts, err = ok.GetInstruments(ctx, &InstrumentsFetchParams{
InstrumentType: okxInstTypeSwap,
})
case asset.Options:
var underlyings []string
underlyings, err = ok.GetPublicUnderlyings(context.Background(), okxInstTypeOption)
if err != nil {
return nil, err
}
for x := range underlyings {
var instruments []Instrument
instruments, err = ok.GetInstruments(ctx, &InstrumentsFetchParams{
InstrumentType: okxInstTypeOption,
Underlying: underlyings[x],
})
if err != nil {
return nil, err
}
insts = append(insts, instruments...)
}
case asset.Margin:
insts, err = ok.GetInstruments(ctx, &InstrumentsFetchParams{
InstrumentType: okxInstTypeMargin,
})
}
insts, err := ok.getInstrumentsForAsset(ctx, a)
if err != nil {
return nil, err
}
@@ -353,6 +322,33 @@ func (ok *Okx) UpdateTradablePairs(ctx context.Context, forceUpdate bool) error
return nil
}
// UpdateOrderExecutionLimits sets exchange execution order limits for an asset type
func (ok *Okx) UpdateOrderExecutionLimits(ctx context.Context, a asset.Item) error {
insts, err := ok.getInstrumentsForAsset(ctx, a)
if err != nil {
return err
}
if len(insts) == 0 {
return errNoInstrumentFound
}
limits := make([]order.MinMaxLevel, len(insts))
for x := range insts {
pair, err := currency.NewPairFromString(insts[x].InstrumentID)
if err != nil {
return err
}
limits[x] = order.MinMaxLevel{
Pair: pair,
Asset: a,
PriceStepIncrementSize: insts[x].TickSize.Float64(),
MinAmount: insts[x].MinimumOrderSize.Float64(),
}
}
return ok.LoadLimits(limits)
}
// UpdateTicker updates and returns the ticker for a currency pair
func (ok *Okx) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error) {
format, err := ok.GetPairFormat(a, false)
@@ -1466,3 +1462,49 @@ func (ok *Okx) GetAvailableTransferChains(ctx context.Context, cryptocurrency cu
}
return chains, nil
}
// getInstrumentsForOptions returns the instruments for options asset type
func (ok *Okx) getInstrumentsForOptions(ctx context.Context) ([]Instrument, error) {
underlyings, err := ok.GetPublicUnderlyings(context.Background(), okxInstTypeOption)
if err != nil {
return nil, err
}
var insts []Instrument
for x := range underlyings {
var instruments []Instrument
instruments, err = ok.GetInstruments(ctx, &InstrumentsFetchParams{
InstrumentType: okxInstTypeOption,
Underlying: underlyings[x],
})
if err != nil {
return nil, err
}
insts = append(insts, instruments...)
}
return insts, nil
}
// getInstrumentsForAsset returns the instruments for an asset type
func (ok *Okx) getInstrumentsForAsset(ctx context.Context, a asset.Item) ([]Instrument, error) {
if !ok.SupportsAsset(a) {
return nil, fmt.Errorf("asset type of %s is not supported by %s", a, ok.Name)
}
var instType string
switch a {
case asset.Options:
return ok.getInstrumentsForOptions(ctx)
case asset.Spot:
instType = okxInstTypeSpot
case asset.Futures:
instType = okxInstTypeFutures
case asset.PerpetualSwap:
instType = okxInstTypeSwap
case asset.Margin:
instType = okxInstTypeMargin
}
return ok.GetInstruments(ctx, &InstrumentsFetchParams{
InstrumentType: instType,
})
}