Bitstamp: Implement UpdateOrderExecutionLimits and testing (#1264)

* Bitstamp: OrderExecutionLimits and testing

* Bitstamp: Fix FetchTradablePairs Loading Limits

* Bitstamp: Limit for the step increment added, type convert replaced with regular expression

* Update exchanges/bitstamp/bitstamp_type_convert.go

Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com>

* Bitstamp: Changed MinimumBaseAmount to MinimumQuoteAmount

* Bitstamp: changed riceStepIncrementSize and AmountStepIncrementSize to math.Pow(-value)

---------

Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com>
This commit is contained in:
Bea
2023-07-28 12:43:32 +07:00
committed by GitHub
parent 1e96453e2a
commit 123ec8c73d
4 changed files with 116 additions and 11 deletions

View File

@@ -210,6 +210,47 @@ func TestFetchTradablePairs(t *testing.T) {
}
}
func TestUpdateTradablePairs(t *testing.T) {
t.Parallel()
if err := b.UpdateTradablePairs(context.Background(), true); err != nil {
t.Error("Bitstamp UpdateTradablePairs() error", err)
}
}
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, 20},
{currency.NewPair(currency.BTC, currency.USDT), 0.01, 20},
},
}
for assetItem, limitTests := range tests {
if err := b.UpdateOrderExecutionLimits(context.Background(), assetItem); err != nil {
t.Errorf("Error fetching %s pairs for test: %v", assetItem, err)
}
for _, limitTest := range limitTests {
limits, err := b.GetOrderExecutionLimits(assetItem, limitTest.pair)
if err != nil {
t.Errorf("Bitstamp GetOrderExecutionLimits() error during TestExecutionLimits; Asset: %s Pair: %s Err: %v", assetItem, limitTest.pair, err)
continue
}
if got := limits.PriceStepIncrementSize; got != limitTest.step {
t.Errorf("Bitstamp UpdateOrderExecutionLimits wrong PriceStepIncrementSize; Asset: %s Pair: %s Expected: %v Got: %v", assetItem, limitTest.pair, limitTest.step, got)
}
if got := limits.MinimumQuoteAmount; got != limitTest.min {
t.Errorf("Bitstamp UpdateOrderExecutionLimits wrong MinAmount; Pair: %s Expected: %v Got: %v", limitTest.pair, limitTest.min, got)
}
}
}
}
func TestGetTransactions(t *testing.T) {
t.Parallel()
_, err := b.GetTransactions(context.Background(),

View File

@@ -0,0 +1,29 @@
package bitstamp
import (
"encoding/json"
"strconv"
"strings"
)
// UnmarshalJSON deserializes JSON, and timestamp information.
func (p *TradingPair) UnmarshalJSON(data []byte) error {
type Alias TradingPair
t := &struct {
*Alias
MinimumOrder string `json:"minimum_order"`
}{
Alias: (*Alias)(p),
}
err := json.Unmarshal(data, t)
if err != nil {
return err
}
minOrderStr := t.MinimumOrder
if prefix, _, found := strings.Cut(t.MinimumOrder, " "); found {
minOrderStr = prefix
}
p.MinimumOrder, err = strconv.ParseFloat(minOrderStr, 64)
return err
}

View File

@@ -55,7 +55,7 @@ type TradingPair struct {
URLSymbol string `json:"url_symbol"`
BaseDecimals int `json:"base_decimals"`
CounterDecimals int `json:"counter_decimals"`
MinimumOrder string `json:"minimum_order"`
MinimumOrder float64
Trading string `json:"trading"`
Description string `json:"description"`
}

View File

@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"math"
"sort"
"strconv"
"sync"
@@ -266,16 +267,19 @@ func (b *Bitstamp) Run(ctx context.Context) {
}
}
if !b.GetEnabledFeatures().AutoPairUpdates && !forceUpdate {
return
if b.GetEnabledFeatures().AutoPairUpdates || forceUpdate {
if err := b.UpdateTradablePairs(ctx, forceUpdate); err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update tradable pairs. Err: %s",
b.Name,
err)
}
}
err := b.UpdateTradablePairs(ctx, forceUpdate)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update tradable pairs. Err: %s",
b.Name,
err)
for _, a := range b.GetAssetTypes(true) {
if err := b.UpdateOrderExecutionLimits(ctx, a); err != nil && err != common.ErrNotYetImplemented {
log.Errorln(log.ExchangeSys, err.Error())
}
}
}
@@ -285,13 +289,12 @@ func (b *Bitstamp) FetchTradablePairs(ctx context.Context, _ asset.Item) (curren
if err != nil {
return nil, err
}
var pair currency.Pair
pairs := make([]currency.Pair, 0, len(symbols))
for x := range symbols {
if symbols[x].Trading != "Enabled" {
continue
}
var pair currency.Pair
pair, err = currency.NewPairFromString(symbols[x].Name)
if err != nil {
return nil, err
@@ -315,6 +318,38 @@ func (b *Bitstamp) UpdateTradablePairs(ctx context.Context, forceUpdate bool) er
return b.EnsureOnePairEnabled()
}
// UpdateOrderExecutionLimits sets exchange execution order limits for an asset type
func (b *Bitstamp) UpdateOrderExecutionLimits(ctx context.Context, a asset.Item) error {
if a != asset.Spot {
return common.ErrNotYetImplemented
}
symbols, err := b.GetTradingPairs(ctx)
if err != nil {
return err
}
limits := make([]order.MinMaxLevel, 0, len(symbols))
for x, info := range symbols {
if symbols[x].Trading != "Enabled" {
continue
}
pair, err := currency.NewPairFromString(symbols[x].Name)
if err != nil {
return err
}
limits = append(limits, order.MinMaxLevel{
Asset: a,
Pair: pair,
PriceStepIncrementSize: math.Pow10(-info.CounterDecimals),
AmountStepIncrementSize: math.Pow10(-info.BaseDecimals),
MinimumQuoteAmount: info.MinimumOrder,
})
}
if err := b.LoadLimits(limits); err != nil {
return fmt.Errorf("%s Error loading exchange limits: %v", b.Name, err)
}
return nil
}
// UpdateTickers updates the ticker for all currency pairs of a given asset type
func (b *Bitstamp) UpdateTickers(_ context.Context, _ asset.Item) error {
return common.ErrFunctionNotSupported