mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-06-06 15:10:59 +00:00
exchange/order/limits: Migrate to new package and integrate with exchanges (#1860)
* move limits, transition to key gen * rollout NewExchangePairAssetKey everywhere * test improvements * self-review fixes * ok, lets go * fix merge issue * slower value func,assertify,drop IsValidPairString * remove binance reference for backtesting test * Redundant nil checks removed due to redundancy * Update order_test.go * Move limits back into /exchanges/ * puts limits in a different box again * SHAZBERT SPECIAL SUGGESTIONS * Update gateio_wrapper.go * fixes all build issues * Many niteroos! * something has gone awry * bugfix * gk's everywhere nits * lint * extra lint * re-remove IsValidPairString * lint fix * standardise test * revert some bads * dupe rm * another revert 360 mcgee * un-in-revertify * Update exchange/order/limits/levels_test.go Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io> * fix * Update exchanges/binance/binance_test.go HERE'S HOPING GITHUB FORMATS THIS CORRECTLY! Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * update text * rn func, same line err gk4202000 --------- Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io> Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com>
This commit is contained in:
@@ -3582,22 +3582,6 @@ func (e *Exchange) InitiateFlashSwapOrderReview(ctx context.Context, arg FlashSw
|
||||
return response, e.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, flashOrderReviewEPL, http.MethodPost, gateioFlashSwapOrdersPreview, nil, &arg, &response)
|
||||
}
|
||||
|
||||
// IsValidPairString returns true if the string represents a valid currency pair
|
||||
func (e *Exchange) IsValidPairString(currencyPair string) bool {
|
||||
if len(currencyPair) < 3 {
|
||||
return false
|
||||
}
|
||||
pf, err := e.CurrencyPairs.GetFormat(asset.Spot, true)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if strings.Contains(currencyPair, pf.Delimiter) {
|
||||
result := strings.Split(currencyPair, pf.Delimiter)
|
||||
return len(result) >= 2
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ********************************* Trading Fee calculation ********************************
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
|
||||
@@ -2473,46 +2473,23 @@ func TestUnlockSubAccount(t *testing.T) {
|
||||
func TestUpdateOrderExecutionLimits(t *testing.T) {
|
||||
t.Parallel()
|
||||
testexch.UpdatePairsOnce(t, e)
|
||||
|
||||
err := e.UpdateOrderExecutionLimits(t.Context(), 1336)
|
||||
require.ErrorIs(t, err, asset.ErrNotSupported)
|
||||
|
||||
err = e.UpdateOrderExecutionLimits(t.Context(), asset.Options)
|
||||
require.ErrorIs(t, err, common.ErrNotYetImplemented)
|
||||
|
||||
err = e.UpdateOrderExecutionLimits(t.Context(), asset.Spot)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
avail, err := e.GetAvailablePairs(asset.Spot)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i := range avail {
|
||||
mm, err := e.GetOrderExecutionLimits(asset.Spot, avail[i])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if mm == (order.MinMaxLevel{}) {
|
||||
t.Fatal("expected a value")
|
||||
}
|
||||
|
||||
if mm.MinimumBaseAmount <= 0 {
|
||||
t.Fatalf("MinimumBaseAmount expected 0 but received %v for %v", mm.MinimumBaseAmount, avail[i])
|
||||
}
|
||||
|
||||
// 1INCH_TRY no minimum quote or base values are returned.
|
||||
|
||||
if mm.QuoteStepIncrementSize <= 0 {
|
||||
t.Fatalf("QuoteStepIncrementSize expected 0 but received %v for %v", mm.QuoteStepIncrementSize, avail[i])
|
||||
}
|
||||
|
||||
if mm.AmountStepIncrementSize <= 0 {
|
||||
t.Fatalf("AmountStepIncrementSize expected 0 but received %v for %v", mm.AmountStepIncrementSize, avail[i])
|
||||
}
|
||||
for _, a := range e.GetAssetTypes(false) {
|
||||
t.Run(a.String(), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
switch a {
|
||||
case asset.Options:
|
||||
return // Options not supported
|
||||
case asset.CrossMargin, asset.Margin:
|
||||
require.ErrorIs(t, e.UpdateOrderExecutionLimits(t.Context(), a), asset.ErrNotSupported)
|
||||
default:
|
||||
require.NoError(t, e.UpdateOrderExecutionLimits(t.Context(), a), "UpdateOrderExecutionLimits must not error")
|
||||
pairs, err := e.CurrencyPairs.GetPairs(a, true)
|
||||
require.NoError(t, err, "GetPairs must not error")
|
||||
l, err := e.GetOrderExecutionLimits(a, pairs[0])
|
||||
require.NoError(t, err, "GetOrderExecutionLimits must not error")
|
||||
assert.Positive(t, l.MinimumBaseAmount, "MinimumBaseAmount should be positive")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -641,7 +641,7 @@ type FuturesContract struct {
|
||||
InDelisting bool `json:"in_delisting"`
|
||||
RiskLimitBase string `json:"risk_limit_base"`
|
||||
InterestRate string `json:"interest_rate"`
|
||||
OrderPriceRound string `json:"order_price_round"`
|
||||
OrderPriceRound types.Number `json:"order_price_round"`
|
||||
OrderSizeMin int64 `json:"order_size_min"`
|
||||
RefRebateRate string `json:"ref_rebate_rate"`
|
||||
FundingInterval int64 `json:"funding_interval"`
|
||||
@@ -845,7 +845,7 @@ type OptionContract struct {
|
||||
Underlying string `json:"underlying"`
|
||||
UnderlyingPrice types.Number `json:"underlying_price"`
|
||||
Multiplier string `json:"multiplier"`
|
||||
OrderPriceRound string `json:"order_price_round"`
|
||||
OrderPriceRound types.Number `json:"order_price_round"`
|
||||
MarkPriceRound string `json:"mark_price_round"`
|
||||
MakerFeeRate string `json:"maker_fee_rate"`
|
||||
TakerFeeRate string `json:"taker_fee_rate"`
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/common/key"
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchange/order/limits"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchange/websocket"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/account"
|
||||
@@ -422,9 +423,6 @@ func (e *Exchange) FetchTradablePairs(ctx context.Context, a asset.Item) (curren
|
||||
continue
|
||||
}
|
||||
p := strings.ToUpper(tradables[x].ID)
|
||||
if !e.IsValidPairString(p) {
|
||||
continue
|
||||
}
|
||||
cp, err := currency.NewPairFromString(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -443,9 +441,6 @@ func (e *Exchange) FetchTradablePairs(ctx context.Context, a asset.Item) (curren
|
||||
continue
|
||||
}
|
||||
p := strings.ToUpper(tradables[x].Base + currency.UnderscoreDelimiter + tradables[x].Quote)
|
||||
if !e.IsValidPairString(p) {
|
||||
continue
|
||||
}
|
||||
cp, err := currency.NewPairFromString(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -468,9 +463,6 @@ func (e *Exchange) FetchTradablePairs(ctx context.Context, a asset.Item) (curren
|
||||
continue
|
||||
}
|
||||
p := strings.ToUpper(contracts[i].Name)
|
||||
if !e.IsValidPairString(p) {
|
||||
continue
|
||||
}
|
||||
cp, err := currency.NewPairFromString(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -489,9 +481,6 @@ func (e *Exchange) FetchTradablePairs(ctx context.Context, a asset.Item) (curren
|
||||
continue
|
||||
}
|
||||
p := strings.ToUpper(contracts[i].Name)
|
||||
if !e.IsValidPairString(p) {
|
||||
continue
|
||||
}
|
||||
cp, err := currency.NewPairFromString(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -511,9 +500,6 @@ func (e *Exchange) FetchTradablePairs(ctx context.Context, a asset.Item) (curren
|
||||
return nil, err
|
||||
}
|
||||
for c := range contracts {
|
||||
if !e.IsValidPairString(contracts[c].Name) {
|
||||
continue
|
||||
}
|
||||
cp, err := currency.NewPairFromString(strings.ReplaceAll(contracts[c].Name, currency.DashDelimiter, currency.UnderscoreDelimiter))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -683,7 +669,7 @@ func (e *Exchange) UpdateOrderbookWithLimit(ctx context.Context, p currency.Pair
|
||||
case asset.Options:
|
||||
o, err = e.GetOptionsOrderbook(ctx, p, "", limit, true)
|
||||
default:
|
||||
return nil, fmt.Errorf("%w %v", asset.ErrNotSupported, a)
|
||||
return nil, fmt.Errorf("%w %q", asset.ErrNotSupported, a)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -1824,7 +1810,7 @@ func (e *Exchange) GetFuturesContractDetails(ctx context.Context, a asset.Item)
|
||||
return nil, futures.ErrNotFuturesAsset
|
||||
}
|
||||
if !e.SupportsAsset(a) {
|
||||
return nil, fmt.Errorf("%w %v", asset.ErrNotSupported, a)
|
||||
return nil, fmt.Errorf("%w %q", asset.ErrNotSupported, a)
|
||||
}
|
||||
settle, err := getSettlementCurrency(currency.EMPTYPAIR, a)
|
||||
if err != nil {
|
||||
@@ -1920,7 +1906,7 @@ func (e *Exchange) GetFuturesContractDetails(ctx context.Context, a asset.Item)
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
return nil, fmt.Errorf("%w %v", asset.ErrNotSupported, a)
|
||||
return nil, fmt.Errorf("%w %q", asset.ErrNotSupported, a)
|
||||
}
|
||||
|
||||
// UpdateOrderExecutionLimits sets exchange executions for a required asset type
|
||||
@@ -1929,7 +1915,7 @@ func (e *Exchange) UpdateOrderExecutionLimits(ctx context.Context, a asset.Item)
|
||||
return fmt.Errorf("%s %w", a, asset.ErrNotSupported)
|
||||
}
|
||||
|
||||
var limits []order.MinMaxLevel
|
||||
var l []limits.MinMaxLevel
|
||||
switch a {
|
||||
case asset.Spot:
|
||||
pairsData, err := e.ListSpotCurrencyPairs(ctx)
|
||||
@@ -1937,7 +1923,7 @@ func (e *Exchange) UpdateOrderExecutionLimits(ctx context.Context, a asset.Item)
|
||||
return err
|
||||
}
|
||||
|
||||
limits = make([]order.MinMaxLevel, 0, len(pairsData))
|
||||
l = make([]limits.MinMaxLevel, 0, len(pairsData))
|
||||
for i := range pairsData {
|
||||
if pairsData[i].TradeStatus == "untradable" {
|
||||
continue
|
||||
@@ -1954,21 +1940,110 @@ func (e *Exchange) UpdateOrderExecutionLimits(ctx context.Context, a asset.Item)
|
||||
minBaseAmount = math.Pow10(-int(pairsData[i].AmountPrecision))
|
||||
}
|
||||
|
||||
limits = append(limits, order.MinMaxLevel{
|
||||
Asset: a,
|
||||
Pair: pair,
|
||||
l = append(l, limits.MinMaxLevel{
|
||||
Key: key.NewExchangeAssetPair(e.Name, a, pair),
|
||||
QuoteStepIncrementSize: math.Pow10(-int(pairsData[i].Precision)),
|
||||
AmountStepIncrementSize: math.Pow10(-int(pairsData[i].AmountPrecision)),
|
||||
MinimumBaseAmount: minBaseAmount,
|
||||
MinimumQuoteAmount: pairsData[i].MinQuoteAmount.Float64(),
|
||||
})
|
||||
}
|
||||
case asset.CoinMarginedFutures:
|
||||
btcContracts, err := e.GetAllFutureContracts(ctx, currency.BTC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l = make([]limits.MinMaxLevel, 0, len(btcContracts))
|
||||
for x := range btcContracts {
|
||||
p := strings.ToUpper(btcContracts[x].Name)
|
||||
cp, err := currency.NewPairFromString(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l = append(l, limits.MinMaxLevel{
|
||||
Key: key.NewExchangeAssetPair(e.Name, a, cp),
|
||||
MinimumBaseAmount: float64(btcContracts[x].OrderSizeMin),
|
||||
MaximumBaseAmount: float64(btcContracts[x].OrderSizeMax),
|
||||
PriceStepIncrementSize: btcContracts[x].OrderPriceRound.Float64(),
|
||||
AmountStepIncrementSize: 1,
|
||||
})
|
||||
}
|
||||
case asset.USDTMarginedFutures:
|
||||
usdtContracts, err := e.GetAllFutureContracts(ctx, currency.USDT)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l = make([]limits.MinMaxLevel, 0, len(usdtContracts))
|
||||
for x := range usdtContracts {
|
||||
p := strings.ToUpper(usdtContracts[x].Name)
|
||||
cp, err := currency.NewPairFromString(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l = append(l, limits.MinMaxLevel{
|
||||
Key: key.NewExchangeAssetPair(e.Name, a, cp),
|
||||
MinimumBaseAmount: float64(usdtContracts[x].OrderSizeMin),
|
||||
MaximumBaseAmount: float64(usdtContracts[x].OrderSizeMax),
|
||||
PriceStepIncrementSize: usdtContracts[x].OrderPriceRound.Float64(),
|
||||
AmountStepIncrementSize: 1,
|
||||
})
|
||||
}
|
||||
case asset.DeliveryFutures:
|
||||
btcContracts, err := e.GetAllDeliveryContracts(ctx, currency.BTC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
usdtContracts, err := e.GetAllDeliveryContracts(ctx, currency.USDT)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
btcContracts = append(btcContracts, usdtContracts...)
|
||||
l = make([]limits.MinMaxLevel, 0, len(btcContracts))
|
||||
for x := range btcContracts {
|
||||
p := strings.ToUpper(btcContracts[x].Name)
|
||||
cp, err := currency.NewPairFromString(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l = append(l, limits.MinMaxLevel{
|
||||
Key: key.NewExchangeAssetPair(e.Name, a, cp),
|
||||
MinimumBaseAmount: float64(btcContracts[x].OrderSizeMin),
|
||||
MaximumBaseAmount: float64(btcContracts[x].OrderSizeMax),
|
||||
PriceStepIncrementSize: btcContracts[x].OrderPriceRound.Float64(),
|
||||
AmountStepIncrementSize: 1,
|
||||
})
|
||||
}
|
||||
case asset.Options:
|
||||
underlyings, err := e.GetAllOptionsUnderlyings(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for x := range underlyings {
|
||||
contracts, err := e.GetAllContractOfUnderlyingWithinExpiryDate(ctx, underlyings[x].Name, time.Time{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l = make([]limits.MinMaxLevel, 0, len(contracts))
|
||||
for c := range contracts {
|
||||
cp, err := currency.NewPairFromString(strings.ReplaceAll(contracts[c].Name, currency.DashDelimiter, currency.UnderscoreDelimiter))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cp.Quote = currency.NewCode(strings.ReplaceAll(cp.Quote.String(), currency.UnderscoreDelimiter, currency.DashDelimiter))
|
||||
l = append(l, limits.MinMaxLevel{
|
||||
Key: key.NewExchangeAssetPair(e.Name, a, cp),
|
||||
MinimumBaseAmount: float64(contracts[c].OrderSizeMin),
|
||||
MaximumBaseAmount: float64(contracts[c].OrderSizeMax),
|
||||
PriceStepIncrementSize: contracts[c].OrderPriceRound.Float64(),
|
||||
AmountStepIncrementSize: 1,
|
||||
})
|
||||
}
|
||||
}
|
||||
default:
|
||||
// TODO: Add in other assets
|
||||
return fmt.Errorf("%s %w", a, common.ErrNotYetImplemented)
|
||||
return fmt.Errorf("%w %q", asset.ErrNotSupported, a)
|
||||
}
|
||||
|
||||
return e.LoadLimits(limits)
|
||||
return limits.Load(l)
|
||||
}
|
||||
|
||||
// GetHistoricalFundingRates returns historical funding rates for a futures contract
|
||||
@@ -2091,11 +2166,7 @@ func (e *Exchange) GetLatestFundingRates(ctx context.Context, r *fundingrate.Lat
|
||||
}
|
||||
resp := make([]fundingrate.LatestRateResponse, 0, len(contracts))
|
||||
for i := range contracts {
|
||||
p := strings.ToUpper(contracts[i].Name)
|
||||
if !e.IsValidPairString(p) {
|
||||
continue
|
||||
}
|
||||
cp, err := currency.NewPairFromString(p)
|
||||
cp, err := currency.NewPairFromString(contracts[i].Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -2183,7 +2254,7 @@ func (e *Exchange) GetOpenInterest(ctx context.Context, keys ...key.PairAsset) (
|
||||
}
|
||||
}
|
||||
resp = append(resp, futures.OpenInterest{
|
||||
Key: key.ExchangePairAsset{
|
||||
Key: key.ExchangeAssetPair{
|
||||
Exchange: e.Name,
|
||||
Base: p.Base.Item,
|
||||
Quote: p.Quote.Item,
|
||||
@@ -2313,7 +2384,7 @@ func (e *Exchange) GetCurrencyTradeURL(_ context.Context, a asset.Item, cp curre
|
||||
}
|
||||
return tradeBaseURL + futuresPath + settle.String() + "/" + cp.Upper().String(), nil
|
||||
default:
|
||||
return "", fmt.Errorf("%w %v", asset.ErrNotSupported, a)
|
||||
return "", fmt.Errorf("%w %q", asset.ErrNotSupported, a)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user