mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-20 23:16:49 +00:00
bithumb: Add basic exchange order execution limits (#726)
* bithumn: Add basic exchange order execution limits * WOW * bithumb: add calculation for minimum amounts based off front end calculations regards @thrasher * bithumb: fix nits
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
@@ -16,6 +17,8 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/common/crypto"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
|
||||
)
|
||||
|
||||
@@ -619,3 +622,41 @@ func (b *Bithumb) GetCandleStick(symbol, interval string) (resp OHLCVResponse, e
|
||||
err = b.SendHTTPRequest(exchange.RestSpot, path, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// FetchExchangeLimits fetches spot order execution limits
|
||||
func (b *Bithumb) FetchExchangeLimits() ([]order.MinMaxLevel, error) {
|
||||
ticks, err := b.GetAllTickers()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var limits []order.MinMaxLevel
|
||||
for code, data := range ticks {
|
||||
c := currency.NewCode(code)
|
||||
cp := currency.NewPair(c, currency.KRW)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
limits = append(limits, order.MinMaxLevel{
|
||||
Pair: cp,
|
||||
Asset: asset.Spot,
|
||||
MinAmount: getAmountMinimum(data.ClosingPrice),
|
||||
})
|
||||
}
|
||||
return limits, nil
|
||||
}
|
||||
|
||||
// getAmountMinimum derives the minimum amount based on current price. This
|
||||
// keeps amount in line with front end, rounded to 4 decimal places. As
|
||||
// transaction policy:
|
||||
// https://en.bithumb.com/customer_support/info_guide?seq=537&categorySeq=302
|
||||
// Seems to not be inline with front end limits.
|
||||
func getAmountMinimum(unitPrice float64) float64 {
|
||||
if unitPrice <= 0 {
|
||||
return 0
|
||||
}
|
||||
ratio := 500 / unitPrice
|
||||
pow := math.Pow(10, float64(4))
|
||||
return math.Ceil(ratio*pow) / pow // Round up our units
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package bithumb
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
@@ -616,3 +617,82 @@ func TestGetHistoricTrades(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateOrderExecutionLimits(t *testing.T) {
|
||||
err := b.UpdateOrderExecutionLimits("")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cp := currency.NewPair(currency.BTC, currency.KRW)
|
||||
limit, err := b.GetOrderExecutionLimits(asset.Spot, cp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = limit.Conforms(46241000, 0.00001, order.Limit)
|
||||
if !errors.Is(err, order.ErrAmountBelowMin) {
|
||||
t.Fatalf("expected error %v but received %v",
|
||||
order.ErrAmountBelowMin,
|
||||
err)
|
||||
}
|
||||
|
||||
err = limit.Conforms(46241000, 0.0001, order.Limit)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("expected error %v but received %v",
|
||||
nil,
|
||||
err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAmountMinimum(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
unitprice float64
|
||||
expected float64
|
||||
}{
|
||||
{
|
||||
name: "ETH-KRW",
|
||||
unitprice: 2638000.0,
|
||||
expected: 0.0002,
|
||||
},
|
||||
{
|
||||
name: "DOGE-KRW",
|
||||
unitprice: 236.5,
|
||||
expected: 2.1142,
|
||||
},
|
||||
{
|
||||
name: "XRP-KRW",
|
||||
unitprice: 818.8,
|
||||
expected: 0.6107,
|
||||
},
|
||||
{
|
||||
name: "LTC-KRW",
|
||||
unitprice: 160100,
|
||||
expected: 0.0032,
|
||||
},
|
||||
{
|
||||
name: "BTC-KRW",
|
||||
unitprice: 46079000,
|
||||
expected: 0.0001,
|
||||
},
|
||||
{
|
||||
name: "nonsense",
|
||||
unitprice: 0,
|
||||
expected: 0,
|
||||
},
|
||||
}
|
||||
|
||||
for i := range testCases {
|
||||
tt := &testCases[i]
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
minAmount := getAmountMinimum(tt.unitprice)
|
||||
if minAmount != tt.expected {
|
||||
t.Fatalf("expected: %f but received: %f for unit price: %f",
|
||||
tt.expected,
|
||||
minAmount,
|
||||
tt.unitprice)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,11 +151,19 @@ func (b *Bithumb) Run() {
|
||||
b.PrintEnabledPairs()
|
||||
}
|
||||
|
||||
err := b.UpdateOrderExecutionLimits("")
|
||||
if err != nil {
|
||||
log.Errorf(log.ExchangeSys,
|
||||
"%s failed to set exchange order execution limits. Err: %v",
|
||||
b.Name,
|
||||
err)
|
||||
}
|
||||
|
||||
if !b.GetEnabledFeatures().AutoPairUpdates {
|
||||
return
|
||||
}
|
||||
|
||||
err := b.UpdateTradablePairs(false)
|
||||
err = b.UpdateTradablePairs(false)
|
||||
if err != nil {
|
||||
log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", b.Name, err)
|
||||
}
|
||||
@@ -797,3 +805,12 @@ func (b *Bithumb) GetHistoricCandles(pair currency.Pair, a asset.Item, start, en
|
||||
func (b *Bithumb) GetHistoricCandlesExtended(pair currency.Pair, a asset.Item, start, end time.Time, interval kline.Interval) (kline.Item, error) {
|
||||
return b.GetHistoricCandles(pair, a, start, end, interval)
|
||||
}
|
||||
|
||||
// UpdateOrderExecutionLimits sets exchange executions for a required asset type
|
||||
func (b *Bithumb) UpdateOrderExecutionLimits(_ asset.Item) error {
|
||||
limits, err := b.FetchExchangeLimits()
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot update exchange execution limits: %w", err)
|
||||
}
|
||||
return b.LoadLimits(limits)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user