bybit: assortment of updates (#1192)

* bybit: cherry-pickable

* bybit: implement fee fetching v5

* bybit: update to use nullable type

* bybit: fix some tests

* bybit: spell check fix

* remove redunant asset dec, and rm output

* rm comment code

* linter: fixerinos woooo

* bybit: constrict rate limit on public spot to v5

* exchanges/bybit/limits: update (CHERRY PICK ME)

* glorious: nIIIIIIIIIIIIIIITS

* glorious: nits continued

* updated comment

* update even more

* RM LINE!

* glorious: nits

* Update exchanges/sharedtestvalues/sharedtestvalues.go

Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>

* fix

---------

Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io>
Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>
This commit is contained in:
Ryan O'Hara-Reid
2023-06-16 12:27:34 +10:00
committed by GitHub
parent 698b6716ea
commit 981a08af83
27 changed files with 1711 additions and 1216 deletions

View File

@@ -1,6 +1,8 @@
package convert
import (
"bytes"
"errors"
"fmt"
"math"
"strconv"
@@ -10,6 +12,10 @@ import (
"github.com/shopspring/decimal"
)
const jsonStringIdent = `"` // immutable byte sequence
var errUnhandledType = errors.New("unhandled type")
// FloatFromString format
func FloatFromString(raw interface{}) (float64, error) {
str, ok := raw.(string)
@@ -187,3 +193,36 @@ func InterfaceToStringOrZeroValue(r interface{}) string {
}
return ""
}
// StringToFloat64 is a float64 that unmarshals from a string. This is useful
// for APIs that return numbers as strings and return an empty string instead of
// 0.
type StringToFloat64 float64
// UnmarshalJSON implements the json.Unmarshaler interface.
// This implementation is slightly more performant than calling json.Unmarshal
// again.
func (f *StringToFloat64) UnmarshalJSON(data []byte) error {
if !bytes.HasPrefix(data, []byte(jsonStringIdent)) {
return fmt.Errorf("%w: %s", errUnhandledType, string(data))
}
data = data[1 : len(data)-1] // Remove quotes
if len(data) == 0 {
*f = StringToFloat64(0)
return nil
}
val, err := strconv.ParseFloat(string(data), 64)
if err != nil {
return err
}
*f = StringToFloat64(val)
return nil
}
// Float64 returns the float64 value of the FloatString.
func (f *StringToFloat64) Float64() float64 {
return float64(*f)
}

View File

@@ -1,6 +1,8 @@
package convert
import (
"encoding/json"
"errors"
"strings"
"testing"
"time"
@@ -315,3 +317,54 @@ func TestInterfaceToStringOrZeroValue(t *testing.T) {
t.Errorf("expected meow, got: %v", x)
}
}
func TestStringToFloat64(t *testing.T) {
t.Parallel()
resp := struct {
Data StringToFloat64 `json:"data"`
}{}
err := json.Unmarshal([]byte(`{"data":"0.00000001"}`), &resp)
if err != nil {
t.Fatal(err)
}
if resp.Data.Float64() != 1e-8 {
t.Fatalf("expected 1e-8, got %v", resp.Data.Float64())
}
err = json.Unmarshal([]byte(`{"data":""}`), &resp)
if err != nil {
t.Fatal(err)
}
err = json.Unmarshal([]byte(`{"data":1337.37}`), &resp)
if !errors.Is(err, errUnhandledType) {
t.Fatalf("received %v but expected %v", err, errUnhandledType)
}
// Demonstrates that a suffix check is not needed.
err = json.Unmarshal([]byte(`{"data":"1337.37}`), &resp)
if err == nil {
t.Fatal("error cannot be nil")
}
err = json.Unmarshal([]byte(`{"data":"MEOW"}`), &resp)
if err == nil {
t.Fatal("error cannot be nil")
}
}
// 2677173 428.9 ns/op 240 B/op 5 allocs/op
func BenchmarkStringToFloat64(b *testing.B) {
resp := struct {
Data StringToFloat64 `json:"data"`
}{}
for i := 0; i < b.N; i++ {
err := json.Unmarshal([]byte(`{"data":"0.00000001"}`), &resp)
if err != nil {
b.Fatal(err)
}
}
}

View File

@@ -1214,8 +1214,8 @@ func (b *Binance) FetchSpotExchangeLimits(ctx context.Context) ([]order.MinMaxLe
l.MultiplierDown = f.MultiplierDown
l.AveragePriceMinutes = f.AvgPriceMinutes
case lotSizeFilter:
l.MaxAmount = f.MaxQty
l.MinAmount = f.MinQty
l.MaximumBaseAmount = f.MaxQty
l.MinimumBaseAmount = f.MinQty
l.AmountStepIncrementSize = f.StepSize
case notionalFilter:
l.MinNotional = f.MinNotional

View File

@@ -1474,8 +1474,8 @@ func (b *Binance) FetchCoinMarginExchangeLimits(ctx context.Context) ([]order.Mi
MinPrice: coinFutures.Symbols[x].Filters[0].MinPrice,
MaxPrice: coinFutures.Symbols[x].Filters[0].MaxPrice,
PriceStepIncrementSize: coinFutures.Symbols[x].Filters[0].TickSize,
MaxAmount: coinFutures.Symbols[x].Filters[1].MaxQty,
MinAmount: coinFutures.Symbols[x].Filters[1].MinQty,
MaximumBaseAmount: coinFutures.Symbols[x].Filters[1].MaxQty,
MinimumBaseAmount: coinFutures.Symbols[x].Filters[1].MinQty,
AmountStepIncrementSize: coinFutures.Symbols[x].Filters[1].StepSize,
MarketMinQty: coinFutures.Symbols[x].Filters[2].MinQty,
MarketMaxQty: coinFutures.Symbols[x].Filters[2].MaxQty,

View File

@@ -2771,11 +2771,11 @@ func TestUpdateOrderExecutionLimits(t *testing.T) {
if limits.PriceStepIncrementSize == 0 {
t.Errorf("Binance UpdateOrderExecutionLimits empty PriceStepIncrementSize; Asset: %s, Pair: %s, Got: %v", a, p, limits.PriceStepIncrementSize)
}
if limits.MinAmount == 0 {
t.Errorf("Binance UpdateOrderExecutionLimits empty MinAmount; Asset: %s, Pair: %s, Got: %v", a, p, limits.MinAmount)
if limits.MinimumBaseAmount == 0 {
t.Errorf("Binance UpdateOrderExecutionLimits empty MinAmount; Asset: %s, Pair: %s, Got: %v", a, p, limits.MinimumBaseAmount)
}
if limits.MaxAmount == 0 {
t.Errorf("Binance UpdateOrderExecutionLimits empty MaxAmount; Asset: %s, Pair: %s, Got: %v", a, p, limits.MaxAmount)
if limits.MaximumBaseAmount == 0 {
t.Errorf("Binance UpdateOrderExecutionLimits empty MaxAmount; Asset: %s, Pair: %s, Got: %v", a, p, limits.MaximumBaseAmount)
}
if limits.AmountStepIncrementSize == 0 {
t.Errorf("Binance UpdateOrderExecutionLimits empty AmountStepIncrementSize; Asset: %s, Pair: %s, Got: %v", a, p, limits.AmountStepIncrementSize)

View File

@@ -1145,8 +1145,8 @@ func (b *Binance) FetchUSDTMarginExchangeLimits(ctx context.Context) ([]order.Mi
MinPrice: usdtFutures.Symbols[x].Filters[0].MinPrice,
MaxPrice: usdtFutures.Symbols[x].Filters[0].MaxPrice,
PriceStepIncrementSize: usdtFutures.Symbols[x].Filters[0].TickSize,
MaxAmount: usdtFutures.Symbols[x].Filters[1].MaxQty,
MinAmount: usdtFutures.Symbols[x].Filters[1].MinQty,
MaximumBaseAmount: usdtFutures.Symbols[x].Filters[1].MaxQty,
MinimumBaseAmount: usdtFutures.Symbols[x].Filters[1].MinQty,
AmountStepIncrementSize: usdtFutures.Symbols[x].Filters[1].StepSize,
MarketMinQty: usdtFutures.Symbols[x].Filters[2].MinQty,
MarketMaxQty: usdtFutures.Symbols[x].Filters[2].MaxQty,

View File

@@ -696,9 +696,9 @@ func (b *Bithumb) FetchExchangeLimits(ctx context.Context) ([]order.MinMaxLevel,
}
limits = append(limits, order.MinMaxLevel{
Pair: cp,
Asset: asset.Spot,
MinAmount: getAmountMinimum(data.ClosingPrice),
Pair: cp,
Asset: asset.Spot,
MinimumBaseAmount: getAmountMinimum(data.ClosingPrice),
})
}
return limits, nil

View File

@@ -1125,8 +1125,8 @@ func (b *BTCMarkets) UpdateOrderExecutionLimits(ctx context.Context, a asset.Ite
limits[x] = order.MinMaxLevel{
Pair: pair,
Asset: asset.Spot,
MinAmount: markets[x].MinOrderAmount,
MaxAmount: markets[x].MaxOrderAmount,
MinimumBaseAmount: markets[x].MinOrderAmount,
MaximumBaseAmount: markets[x].MaxOrderAmount,
AmountStepIncrementSize: math.Pow(10, -markets[x].AmountDecimals),
PriceStepIncrementSize: math.Pow(10, -markets[x].PriceDecimals),
}

View File

@@ -14,6 +14,7 @@ import (
"time"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/common/convert"
"github.com/thrasher-corp/gocryptotrader/common/crypto"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
@@ -42,6 +43,7 @@ const (
bybit24HrsChange = "/spot/quote/v1/ticker/24hr"
bybitLastTradedPrice = "/spot/quote/v1/ticker/price"
bybitBestBidAskPrice = "/spot/quote/v1/ticker/book_ticker"
bybitGetTickersV5 = "/v5/market/tickers"
// Authenticated endpoints
bybitSpotOrder = "/spot/v1/order" // create, query, cancel
@@ -53,12 +55,18 @@ const (
bybitTradeHistory = "/spot/v1/myTrades"
bybitWalletBalance = "/spot/v1/account"
bybitServerTime = "/spot/v1/time"
bybitAccountFee = "/v5/account/fee-rate"
// Account asset endpoint
bybitGetDepositAddress = "/asset/v1/private/deposit/address"
bybitWithdrawFund = "/asset/v1/private/withdraw"
)
var (
errCategoryNotSet = errors.New("category not set")
errBaseNotSet = errors.New("base coin not set when category is option")
)
// GetAllSpotPairs gets all pairs on the exchange
func (by *Bybit) GetAllSpotPairs(ctx context.Context) ([]PairData, error) {
resp := struct {
@@ -153,10 +161,10 @@ func (by *Bybit) GetMergedOrderBook(ctx context.Context, symbol string, scale, d
func (by *Bybit) GetTrades(ctx context.Context, symbol string, limit int64) ([]TradeItem, error) {
resp := struct {
Data []struct {
Price float64 `json:"price,string"`
Time bybitTimeMilliSec `json:"time"`
Quantity float64 `json:"qty,string"`
IsBuyerMaker bool `json:"isBuyerMaker"`
Price convert.StringToFloat64 `json:"price"`
Time bybitTimeMilliSec `json:"time"`
Quantity convert.StringToFloat64 `json:"qty"`
IsBuyerMaker bool `json:"isBuyerMaker"`
} `json:"result"`
Error
}{}
@@ -186,9 +194,9 @@ func (by *Bybit) GetTrades(ctx context.Context, symbol string, limit int64) ([]T
trades[x] = TradeItem{
CurrencyPair: symbol,
Price: resp.Data[x].Price,
Price: resp.Data[x].Price.Float64(),
Side: tradeSide,
Volume: resp.Data[x].Quantity,
Volume: resp.Data[x].Quantity.Float64(),
Time: resp.Data[x].Time.Time(),
}
}
@@ -314,23 +322,9 @@ func (by *Bybit) GetKlines(ctx context.Context, symbol, period string, limit int
// Get24HrsChange returns price change statistics for the last 24 hours
// If symbol not passed then it will return price change statistics for all pairs
func (by *Bybit) Get24HrsChange(ctx context.Context, symbol string) ([]PriceChangeStats, error) {
type priceChangeStats struct {
Time bybitTimeMilliSec `json:"time"`
Symbol string `json:"symbol"`
BestBidPrice float64 `json:"bestBidPrice,string"`
BestAskPrice float64 `json:"bestAskPrice,string"`
LastPrice float64 `json:"lastPrice,string"`
OpenPrice float64 `json:"openPrice,string"`
HighPrice float64 `json:"highPrice,string"`
LowPrice float64 `json:"lowPrice,string"`
Volume float64 `json:"volume,string"`
QuoteVolume float64 `json:"quoteVolume,string"`
}
var stats []PriceChangeStats
if symbol != "" {
resp := struct {
Data priceChangeStats `json:"result"`
Data PriceChangeStats `json:"result"`
Error
}{}
@@ -341,46 +335,20 @@ func (by *Bybit) Get24HrsChange(ctx context.Context, symbol string) ([]PriceChan
if err != nil {
return nil, err
}
stats = append(stats, PriceChangeStats{
resp.Data.Time.Time(),
resp.Data.Symbol,
resp.Data.BestAskPrice,
resp.Data.BestAskPrice,
resp.Data.LastPrice,
resp.Data.OpenPrice,
resp.Data.HighPrice,
resp.Data.LowPrice,
resp.Data.Volume,
resp.Data.QuoteVolume,
})
} else {
resp := struct {
Data []priceChangeStats `json:"result"`
Error
}{}
err := by.SendHTTPRequest(ctx, exchange.RestSpot, bybit24HrsChange, publicSpotRate, &resp)
if err != nil {
return nil, err
}
for x := range resp.Data {
stats = append(stats, PriceChangeStats{
resp.Data[x].Time.Time(),
resp.Data[x].Symbol,
resp.Data[x].BestAskPrice,
resp.Data[x].BestAskPrice,
resp.Data[x].LastPrice,
resp.Data[x].OpenPrice,
resp.Data[x].HighPrice,
resp.Data[x].LowPrice,
resp.Data[x].Volume,
resp.Data[x].QuoteVolume,
})
}
return []PriceChangeStats{resp.Data}, nil
}
return stats, nil
resp := struct {
Data []PriceChangeStats `json:"result"`
Error
}{}
err := by.SendHTTPRequest(ctx, exchange.RestSpot, bybit24HrsChange, publicSpotRate, &resp)
if err != nil {
return nil, err
}
return resp.Data, nil
}
// GetLastTradedPrice returns last trading price
@@ -427,19 +395,9 @@ func (by *Bybit) GetLastTradedPrice(ctx context.Context, symbol string) ([]LastT
// GetBestBidAskPrice returns best BID and ASK price
// If symbol not passed then it will return best BID and ASK price for all pairs
func (by *Bybit) GetBestBidAskPrice(ctx context.Context, symbol string) ([]TickerData, error) {
type bestTicker struct {
Symbol string `json:"symbol"`
BidPrice float64 `json:"bidPrice,string"`
BidQuantity float64 `json:"bidQty,string"`
AskPrice float64 `json:"askPrice,string"`
AskQuantity float64 `json:"askQty,string"`
Time bybitTimeMilliSec `json:"time"`
}
var tickers []TickerData
if symbol != "" {
resp := struct {
Data bestTicker `json:"result"`
Data TickerData `json:"result"`
Error
}{}
@@ -450,36 +408,55 @@ func (by *Bybit) GetBestBidAskPrice(ctx context.Context, symbol string) ([]Ticke
if err != nil {
return nil, err
}
tickers = append(tickers, TickerData{
resp.Data.Symbol,
resp.Data.BidPrice,
resp.Data.BidQuantity,
resp.Data.AskPrice,
resp.Data.AskQuantity,
resp.Data.Time.Time(),
})
} else {
resp := struct {
Data []bestTicker `json:"result"`
Error
}{}
err := by.SendHTTPRequest(ctx, exchange.RestSpot, bybitBestBidAskPrice, publicSpotRate, &resp)
if err != nil {
return nil, err
}
for x := range resp.Data {
tickers = append(tickers, TickerData{
resp.Data[x].Symbol,
resp.Data[x].BidPrice,
resp.Data[x].BidQuantity,
resp.Data[x].AskPrice,
resp.Data[x].AskQuantity,
resp.Data[x].Time.Time(),
})
}
return []TickerData{resp.Data}, nil
}
return tickers, nil
resp := struct {
Data []TickerData `json:"result"`
Error
}{}
err := by.SendHTTPRequest(ctx, exchange.RestSpot, bybitBestBidAskPrice, publicSpotRate, &resp)
if err != nil {
return nil, err
}
return resp.Data, nil
}
// GetTickersV5 returns tickers for either "spot", "option" or "inverse".
// Specific symbol is optional.
func (by *Bybit) GetTickersV5(ctx context.Context, category, symbol, baseCoin string) (*ListOfTickers, error) {
if category == "" {
return nil, errCategoryNotSet
}
if category == "option" && baseCoin == "" {
return nil, errBaseNotSet
}
val := url.Values{}
val.Set("category", category)
if symbol != "" {
val.Set("symbol", symbol)
}
if baseCoin != "" {
val.Set("baseCoin", baseCoin)
}
result := struct {
Data *ListOfTickers `json:"result"`
Error
}{}
err := by.SendHTTPRequest(ctx, exchange.RestSpot, bybitGetTickersV5+"?"+val.Encode(), publicSpotRate, &result)
if err != nil {
return nil, err
}
return result.Data, nil
}
// CreatePostOrder create and post order
@@ -789,6 +766,42 @@ func (by *Bybit) WithdrawFund(ctx context.Context, coin, chain, address, tag, am
return resp.Data.ID, by.SendAuthHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, bybitWithdrawFund, nil, params, &resp, privateSpotRate)
}
// GetFeeRate returns user account fee
// Valid category: "spot", "linear", "inverse", "option"
func (by *Bybit) GetFeeRate(ctx context.Context, category, symbol, baseCoin string) (*AccountFee, error) {
if category == "" {
return nil, errCategoryNotSet
}
if !common.StringDataContains(validCategory, category) {
// NOTE: Opted to fail here because if the user passes in an invalid
// category the error returned is this
// `Bybit raw response: {"retCode":10005,"retMsg":"Permission denied, please check your API key permissions.","result":{},"retExtInfo":{},"time":1683694010783}`
return nil, fmt.Errorf("%w, valid category values are %v", errInvalidCategory, validCategory)
}
params := url.Values{}
params.Set("category", category)
if symbol != "" {
params.Set("symbol", symbol)
}
if baseCoin != "" {
params.Set("baseCoin", baseCoin)
}
result := struct {
Data *AccountFee `json:"result"`
Error
}{}
err := by.SendAuthHTTPRequestV5(ctx, exchange.RestSpot, http.MethodGet, bybitAccountFee, params, &result, privateFeeRate)
if err != nil {
return nil, err
}
return result.Data, nil
}
// SendHTTPRequest sends an unauthenticated request
func (by *Bybit) SendHTTPRequest(ctx context.Context, ePath exchange.URL, path string, f request.EndpointLimit, result UnmarshalTo) error {
endpointPath, err := by.API.Endpoints.GetURL(ePath)
@@ -842,8 +855,8 @@ func (by *Bybit) SendAuthHTTPRequest(ctx context.Context, ePath exchange.URL, me
var (
payload []byte
hmacSignedStr string
headers = make(map[string]string)
)
headers := make(map[string]string)
if jsonPayload != nil {
headers["Content-Type"] = "application/json"
@@ -893,19 +906,71 @@ func (by *Bybit) SendAuthHTTPRequest(ctx context.Context, ePath exchange.URL, me
return result.GetError()
}
// SendAuthHTTPRequestV5 sends an authenticated HTTP request
func (by *Bybit) SendAuthHTTPRequestV5(ctx context.Context, ePath exchange.URL, method, path string, params url.Values, result UnmarshalTo, f request.EndpointLimit) error {
creds, err := by.GetCredentials(ctx)
if err != nil {
return err
}
if result == nil {
result = &Error{}
}
endpointPath, err := by.API.Endpoints.GetURL(ePath)
if err != nil {
return err
}
err = by.SendPayload(ctx, f, func() (*request.Item, error) {
timestamp := strconv.FormatInt(time.Now().UnixMilli(), 10)
headers := make(map[string]string)
headers["Content-Type"] = "application/x-www-form-urlencoded"
headers["X-BAPI-TIMESTAMP"] = timestamp
headers["X-BAPI-API-KEY"] = creds.Key
headers["X-BAPI-RECV-WINDOW"] = defaultRecvWindow
var hmacSignedStr string
hmacSignedStr, err = getSign(timestamp+creds.Key+defaultRecvWindow+params.Encode(), creds.Secret)
if err != nil {
return nil, err
}
headers["X-BAPI-SIGN"] = hmacSignedStr
return &request.Item{
Method: method,
Path: endpointPath + common.EncodeURLValues(path, params),
Headers: headers,
Result: &result,
AuthRequest: true,
Verbose: by.Verbose,
HTTPDebugging: by.HTTPDebugging,
HTTPRecording: by.HTTPRecording}, nil
})
if err != nil {
return err
}
return result.GetError()
}
// Error defines all error information for each request
type Error struct {
ReturnCode int64 `json:"ret_code"`
ReturnMsg string `json:"ret_msg"`
ExtCode string `json:"ext_code"`
ExtMsg string `json:"ext_info"`
ReturnCode int64 `json:"ret_code"`
ReturnMsg string `json:"ret_msg"`
ReturnCodeV5 int64 `json:"retCode"`
ReturnMessageV5 string `json:"retMsg"`
ExtCode string `json:"ext_code"`
ExtMsg string `json:"ext_info"`
}
// GetError checks and returns an error if it is supplied.
func (e Error) GetError() error {
func (e *Error) GetError() error {
if e.ReturnCode != 0 && e.ReturnMsg != "" {
return errors.New(e.ReturnMsg)
}
if e.ReturnCodeV5 != 0 && e.ReturnMessageV5 != "" {
return errors.New(e.ReturnMessageV5)
}
if e.ExtCode != "" && e.ExtMsg != "" {
return errors.New(e.ExtMsg)
}

View File

@@ -10,6 +10,7 @@ import (
"time"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/common/convert"
"github.com/thrasher-corp/gocryptotrader/currency"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
@@ -98,12 +99,12 @@ func (by *Bybit) GetFuturesOrderbook(ctx context.Context, symbol currency.Pair)
switch data.Result[x].Side {
case sideBuy:
resp.Bids = append(resp.Bids, orderbook.Item{
Price: data.Result[x].Price,
Price: data.Result[x].Price.Float64(),
Amount: data.Result[x].Size,
})
case sideSell:
resp.Asks = append(resp.Asks, orderbook.Item{
Price: data.Result[x].Price,
Price: data.Result[x].Price.Float64(),
Amount: data.Result[x].Size,
})
default:
@@ -393,7 +394,7 @@ func (by *Bybit) GetLastFundingRate(ctx context.Context, symbol currency.Pair) (
// GetFuturesServerTime returns Bybit server time in seconds
func (by *Bybit) GetFuturesServerTime(ctx context.Context) (time.Time, error) {
resp := struct {
TimeNow float64 `json:"time_now,string"`
TimeNow convert.StringToFloat64 `json:"time_now"`
Error
}{}
@@ -401,7 +402,7 @@ func (by *Bybit) GetFuturesServerTime(ctx context.Context) (time.Time, error) {
if err != nil {
return time.Time{}, err
}
sec, dec := math.Modf(resp.TimeNow)
sec, dec := math.Modf(resp.TimeNow.Float64())
return time.Unix(int64(sec), int64(dec*(1e9))), nil
}
@@ -1085,24 +1086,21 @@ func (by *Bybit) ChangeCoinMargin(ctx context.Context, symbol currency.Pair, buy
}
// GetTradingFeeRate returns trading taker and maker fee rate
func (by *Bybit) GetTradingFeeRate(ctx context.Context, symbol currency.Pair) (takerFee, makerFee float64, err error) {
func (by *Bybit) GetTradingFeeRate(ctx context.Context, symbol currency.Pair) (*CFuturesTradingFeeRate, error) {
params := url.Values{}
resp := struct {
Result struct {
TakerFeeRate float64 `json:"taker_fee_rate,string"`
MakerFeeRate float64 `json:"maker_fee_rate,string"`
} `json:"result"`
Result *CFuturesTradingFeeRate `json:"result"`
Error
}{}
symbolValue, err := by.FormatSymbol(symbol, asset.CoinMarginedFutures)
if err != nil {
return resp.Result.TakerFeeRate, resp.Result.MakerFeeRate, err
return nil, err
}
params.Set("symbol", symbolValue)
takerFee, makerFee, err = resp.Result.TakerFeeRate, resp.Result.MakerFeeRate, by.SendAuthHTTPRequest(ctx, exchange.RestCoinMargined, http.MethodGet, bybitFuturesAPIVersion+cfuturesGetTradingFeeRate, params, nil, &resp, cFuturesGetTradingFeeRate)
return
return resp.Result,
by.SendAuthHTTPRequest(ctx, exchange.RestCoinMargined, http.MethodGet, bybitFuturesAPIVersion+cfuturesGetTradingFeeRate, params, nil, &resp, cFuturesGetTradingFeeRate)
}
// SetCoinRiskLimit sets risk limit

View File

@@ -19,6 +19,7 @@ import (
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
"github.com/thrasher-corp/gocryptotrader/portfolio/withdraw"
)
@@ -60,6 +61,20 @@ func TestMain(m *testing.M) {
log.Fatal(err)
}
// Turn on all pairs for testing
supportedAssets := b.GetAssetTypes(false)
for x := range supportedAssets {
avail, err := b.GetAvailablePairs(supportedAssets[x])
if err != nil {
log.Fatal(err)
}
err = b.CurrencyPairs.StorePairs(supportedAssets[x], avail, true)
if err != nil {
log.Fatal(err)
}
}
os.Exit(m.Run())
}
@@ -1055,10 +1070,18 @@ func TestGetTradingFeeRate(t *testing.T) {
t.Fatal(err)
}
_, _, err = b.GetTradingFeeRate(context.Background(), pair)
feeRate, err := b.GetTradingFeeRate(context.Background(), pair)
if err != nil {
t.Error(err)
}
if feeRate.MakerFeeRate == 0 && feeRate.TakerFeeRate == 0 {
t.Error("expected fee rate")
}
if feeRate.UserID == 0 {
t.Error("expected user id")
}
}
func TestSetCoinRiskLimit(t *testing.T) {
@@ -3309,3 +3332,137 @@ func TestGetUSDCPredictedFundingRate(t *testing.T) {
t.Error(err)
}
}
func TestUpdateTickers(t *testing.T) {
t.Parallel()
supportedAssets := b.GetAssetTypes(false)
ctx := context.Background()
for x := range supportedAssets {
err := b.UpdateTickers(ctx, supportedAssets[x])
if err != nil {
t.Fatalf("%v %v\n", supportedAssets[x], err)
}
avail, err := b.GetAvailablePairs(supportedAssets[x])
if err != nil {
t.Fatalf("%v %v\n", supportedAssets[x], err)
}
for y := range avail {
_, err = ticker.GetTicker(b.GetName(), avail[y], supportedAssets[x])
if err != nil {
t.Fatalf("%v %v %v\n", avail[y], supportedAssets[x], err)
}
}
}
}
func TestGetTickersV5(t *testing.T) {
t.Parallel()
_, err := b.GetTickersV5(context.Background(), "bruh", "", "")
if err != nil && err.Error() != "Illegal category" {
t.Error(err)
}
_, err = b.GetTickersV5(context.Background(), "option", "", "")
if !errors.Is(err, errBaseNotSet) {
t.Fatalf("expected: %v, received: %v", errBaseNotSet, err)
}
_, err = b.GetTickersV5(context.Background(), "spot", "", "")
if err != nil {
t.Error(err)
}
_, err = b.GetTickersV5(context.Background(), "option", "", "BTC")
if err != nil {
t.Error(err)
}
_, err = b.GetTickersV5(context.Background(), "inverse", "", "")
if err != nil {
t.Error(err)
}
_, err = b.GetTickersV5(context.Background(), "linear", "", "")
if err != nil {
t.Error(err)
}
}
func TestUpdateOrderExecutionLimits(t *testing.T) {
t.Parallel()
err := b.UpdateOrderExecutionLimits(context.Background(), asset.USDCMarginedFutures)
if !errors.Is(err, asset.ErrNotSupported) {
t.Fatalf("received: %v expected: %v", err, asset.ErrNotSupported)
}
err = b.UpdateOrderExecutionLimits(context.Background(), asset.Spot)
if err != nil {
t.Error("Okx UpdateOrderExecutionLimits() error", err)
}
avail, err := b.GetAvailablePairs(asset.Spot)
if err != nil {
t.Fatal("Okx GetAvailablePairs() error", err)
}
for x := range avail {
limits, err := b.GetOrderExecutionLimits(asset.Spot, avail[x])
if err != nil {
t.Fatal("Okx GetOrderExecutionLimits() error", err)
}
if limits == (order.MinMaxLevel{}) {
t.Fatal("Okx GetOrderExecutionLimits() error cannot be nil")
}
}
}
func TestGetFeeRate(t *testing.T) {
t.Parallel()
_, err := b.GetFeeRate(context.Background(), "", "", "")
if !errors.Is(err, errCategoryNotSet) {
t.Fatalf("received %v but expected %v", err, errCategoryNotSet)
}
_, err = b.GetFeeRate(context.Background(), "bruh", "", "")
if !errors.Is(err, errInvalidCategory) {
t.Fatalf("received %v but expected %v", err, errInvalidCategory)
}
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
_, err = b.GetFeeRate(context.Background(), "spot", "", "")
if !errors.Is(err, nil) {
t.Errorf("received %v but expected %v", err, nil)
}
_, err = b.GetFeeRate(context.Background(), "linear", "", "")
if !errors.Is(err, nil) {
t.Errorf("received %v but expected %v", err, nil)
}
_, err = b.GetFeeRate(context.Background(), "inverse", "", "")
if !errors.Is(err, nil) {
t.Errorf("received %v but expected %v", err, nil)
}
_, err = b.GetFeeRate(context.Background(), "option", "", "ETH")
if !errors.Is(err, nil) {
t.Errorf("received %v but expected %v", err, nil)
}
}
func TestForceFileStandard(t *testing.T) {
t.Parallel()
err := sharedtestvalues.ForceFileStandard(t, sharedtestvalues.EmptyStringPotentialPattern)
if err != nil {
t.Error(err)
}
if t.Failed() {
t.Fatal("Please use convert.StringToFloat64 type instead of `float64` and remove `,string` as strings can be empty in unmarshal process. Then call the Float64() method.")
}
}

View File

@@ -6,6 +6,7 @@ import (
"strconv"
"time"
"github.com/thrasher-corp/gocryptotrader/common/convert"
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
)
@@ -44,6 +45,8 @@ var (
errExpectedOneOrder = errors.New("expected one order")
)
var validCategory = []string{"spot", "linear", "inverse", "option"}
// bybitTimeSec provides an internal conversion helper
type bybitTimeSec time.Time
@@ -149,34 +152,6 @@ func (b bybitTimeNanoSec) Time() time.Time {
return time.Time(b)
}
// bybitNumericalValue is a type used for when the API returns an empty or
// numerical string
type bybitNumericalValue float64
// UnmarshalJSON is custom type json unmarshaller for bybitNumericalValue
func (b *bybitNumericalValue) UnmarshalJSON(data []byte) error {
var num string
err := json.Unmarshal(data, &num)
if err != nil {
return err
}
if num == "" {
return nil
}
v, err := strconv.ParseFloat(num, 64)
if err != nil {
return err
}
*b = bybitNumericalValue(v)
return nil
}
// Float64 returns a float64 value for bybitNumericalValue
func (b *bybitNumericalValue) Float64() float64 { return float64(*b) }
// UnmarshalTo acts as interface to exchange API response
type UnmarshalTo interface {
GetError() error
@@ -184,19 +159,19 @@ type UnmarshalTo interface {
// PairData stores pair data
type PairData struct {
Name string `json:"name"`
Alias string `json:"alias"`
BaseCurrency string `json:"baseCurrency"`
QuoteCurrency string `json:"quoteCurrency"`
BasePrecision float64 `json:"basePrecision,string"`
QuotePrecision float64 `json:"quotePrecision,string"`
MinTradeQuantity float64 `json:"minTradeQuantity,string"`
MinTradeAmount float64 `json:"minTradeAmount,string"`
MinPricePrecision float64 `json:"minPricePrecision,string"`
MaxTradeQuantity float64 `json:"maxTradeQuantity,string"`
MaxTradeAmount float64 `json:"maxTradeAmount,string"`
Category int64 `json:"category"`
ShowStatus bool `json:"showStatus"`
Name string `json:"name"`
Alias string `json:"alias"`
BaseCurrency string `json:"baseCurrency"`
QuoteCurrency string `json:"quoteCurrency"`
BasePrecision convert.StringToFloat64 `json:"basePrecision"`
QuotePrecision convert.StringToFloat64 `json:"quotePrecision"`
MinTradeQuantity convert.StringToFloat64 `json:"minTradeQuantity"`
MinTradeAmount convert.StringToFloat64 `json:"minTradeAmount"`
MinPricePrecision convert.StringToFloat64 `json:"minPricePrecision"`
MaxTradeQuantity convert.StringToFloat64 `json:"maxTradeQuantity"`
MaxTradeAmount convert.StringToFloat64 `json:"maxTradeAmount"`
Category int64 `json:"category"`
ShowStatus bool `json:"showStatus"`
}
// Orderbook stores the orderbook data
@@ -233,32 +208,32 @@ type KlineItem struct {
// PriceChangeStats contains statistics for the last 24 hours trade
type PriceChangeStats struct {
Time time.Time
Symbol string
BestBidPrice float64
BestAskPrice float64
LastPrice float64
OpenPrice float64
HighPrice float64
LowPrice float64
Volume float64
QuoteVolume float64
Time bybitTimeMilliSec `json:"time"`
Symbol string `json:"symbol"`
BestBidPrice convert.StringToFloat64 `json:"bestBidPrice"`
BestAskPrice convert.StringToFloat64 `json:"bestAskPrice"`
LastPrice convert.StringToFloat64 `json:"lastPrice"`
OpenPrice convert.StringToFloat64 `json:"openPrice"`
HighPrice convert.StringToFloat64 `json:"highPrice"`
LowPrice convert.StringToFloat64 `json:"lowPrice"`
Volume convert.StringToFloat64 `json:"volume"`
QuoteVolume convert.StringToFloat64 `json:"quoteVolume"`
}
// LastTradePrice contains price for last trade
type LastTradePrice struct {
Symbol string `json:"symbol"`
Price float64 `json:"price,string"`
Symbol string `json:"symbol"`
Price convert.StringToFloat64 `json:"price"`
}
// TickerData stores ticker data
type TickerData struct {
Symbol string
BidPrice float64
BidQuantity float64
AskPrice float64
AskQuantity float64
Time time.Time
Symbol string `json:"symbol"`
BidPrice convert.StringToFloat64 `json:"bidPrice"`
BidQuantity convert.StringToFloat64 `json:"bidQty"`
AskPrice convert.StringToFloat64 `json:"askPrice"`
AskQuantity convert.StringToFloat64 `json:"askQty"`
Time bybitTimeMilliSec `json:"time"`
}
var (
@@ -296,97 +271,97 @@ type PlaceOrderRequest struct {
// PlaceOrderResponse store new order response type
type PlaceOrderResponse struct {
OrderID string `json:"orderId"`
OrderLinkID string `json:"orderLinkId"`
Symbol string `json:"symbol"`
Time bybitTimeMilliSecStr `json:"transactTime"`
Price float64 `json:"price,string"`
Quantity float64 `json:"origQty,string"`
TradeType string `json:"type"`
Side string `json:"side"`
Status string `json:"status"`
TimeInForce string `json:"timeInForce"`
AccountID string `json:"accountId"`
SymbolName string `json:"symbolName"`
ExecutedQty float64 `json:"executedQty,string"`
OrderID string `json:"orderId"`
OrderLinkID string `json:"orderLinkId"`
Symbol string `json:"symbol"`
Time bybitTimeMilliSecStr `json:"transactTime"`
Price convert.StringToFloat64 `json:"price"`
Quantity convert.StringToFloat64 `json:"origQty"`
TradeType string `json:"type"`
Side string `json:"side"`
Status string `json:"status"`
TimeInForce string `json:"timeInForce"`
AccountID string `json:"accountId"`
SymbolName string `json:"symbolName"`
ExecutedQty convert.StringToFloat64 `json:"executedQty"`
}
// QueryOrderResponse holds query order data
type QueryOrderResponse struct {
AccountID string `json:"accountId"`
ExchangeID string `json:"exchangeId"`
Symbol string `json:"symbol"`
SymbolName string `json:"symbolName"`
OrderLinkID string `json:"orderLinkId"`
OrderID string `json:"orderId"`
Price float64 `json:"price,string"`
Quantity float64 `json:"origQty,string"`
ExecutedQty float64 `json:"executedQty,string"`
CummulativeQuoteQty float64 `json:"cummulativeQuoteQty,string"`
AveragePrice float64 `json:"avgPrice,string"`
Status string `json:"status"`
TimeInForce string `json:"timeInForce"`
TradeType string `json:"type"`
Side string `json:"side"`
StopPrice float64 `json:"stopPrice,string"`
IcebergQty float64 `json:"icebergQty,string"`
Time bybitTimeMilliSecStr `json:"time"`
UpdateTime bybitTimeMilliSecStr `json:"updateTime"`
IsWorking bool `json:"isWorking"`
AccountID string `json:"accountId"`
ExchangeID string `json:"exchangeId"`
Symbol string `json:"symbol"`
SymbolName string `json:"symbolName"`
OrderLinkID string `json:"orderLinkId"`
OrderID string `json:"orderId"`
Price convert.StringToFloat64 `json:"price"`
Quantity convert.StringToFloat64 `json:"origQty"`
ExecutedQty convert.StringToFloat64 `json:"executedQty"`
CummulativeQuoteQty convert.StringToFloat64 `json:"cummulativeQuoteQty"`
AveragePrice convert.StringToFloat64 `json:"avgPrice"`
Status string `json:"status"`
TimeInForce string `json:"timeInForce"`
TradeType string `json:"type"`
Side string `json:"side"`
StopPrice convert.StringToFloat64 `json:"stopPrice"`
IcebergQty convert.StringToFloat64 `json:"icebergQty"`
Time bybitTimeMilliSecStr `json:"time"`
UpdateTime bybitTimeMilliSecStr `json:"updateTime"`
IsWorking bool `json:"isWorking"`
}
// CancelOrderResponse is the return structured response from the exchange
type CancelOrderResponse struct {
OrderID string `json:"orderId"`
OrderLinkID string `json:"orderLinkId"`
Symbol string `json:"symbol"`
Status string `json:"status"`
AccountID string `json:"accountId"`
Time bybitTimeMilliSecStr `json:"transactTime"`
Price float64 `json:"price,string"`
Quantity float64 `json:"origQty,string"`
ExecutedQty float64 `json:"executedQty,string"`
TimeInForce string `json:"timeInForce"`
TradeType string `json:"type"`
Side string `json:"side"`
OrderID string `json:"orderId"`
OrderLinkID string `json:"orderLinkId"`
Symbol string `json:"symbol"`
Status string `json:"status"`
AccountID string `json:"accountId"`
Time bybitTimeMilliSecStr `json:"transactTime"`
Price convert.StringToFloat64 `json:"price"`
Quantity convert.StringToFloat64 `json:"origQty"`
ExecutedQty convert.StringToFloat64 `json:"executedQty"`
TimeInForce string `json:"timeInForce"`
TradeType string `json:"type"`
Side string `json:"side"`
}
// HistoricalTrade holds recent trade data
type HistoricalTrade struct {
Symbol string `json:"symbol"`
ID string `json:"id"`
OrderID string `json:"orderId"`
TicketID string `json:"ticketId"`
Price float64 `json:"price,string"`
Quantity float64 `json:"qty,string"`
Commission float64 `json:"commission,string"`
CommissionAsset float64 `json:"commissionAsset,string"`
Time bybitTimeMilliSecStr `json:"time"`
IsBuyer bool `json:"isBuyer"`
IsMaker bool `json:"isMaker"`
SymbolName string `json:"symbolName"`
MatchOrderID string `json:"matchOrderId"`
Fee FeeData `json:"fee"`
FeeTokenID string `json:"feeTokenId"`
FeeAmount float64 `json:"feeAmount,string"`
MakerRebate float64 `json:"makerRebate,string"`
Symbol string `json:"symbol"`
ID string `json:"id"`
OrderID string `json:"orderId"`
TicketID string `json:"ticketId"`
Price convert.StringToFloat64 `json:"price"`
Quantity convert.StringToFloat64 `json:"qty"`
Commission convert.StringToFloat64 `json:"commission"`
CommissionAsset convert.StringToFloat64 `json:"commissionAsset"`
Time bybitTimeMilliSecStr `json:"time"`
IsBuyer bool `json:"isBuyer"`
IsMaker bool `json:"isMaker"`
SymbolName string `json:"symbolName"`
MatchOrderID string `json:"matchOrderId"`
Fee FeeData `json:"fee"`
FeeTokenID string `json:"feeTokenId"`
FeeAmount convert.StringToFloat64 `json:"feeAmount"`
MakerRebate convert.StringToFloat64 `json:"makerRebate"`
}
// FeeData store fees data
type FeeData struct {
FeeTokenID int64 `json:"feeTokenId"`
FeeTokenName string `json:"feeTokenName"`
Fee float64 `json:"fee,string"`
FeeTokenID int64 `json:"feeTokenId"`
FeeTokenName string `json:"feeTokenName"`
Fee convert.StringToFloat64 `json:"fee"`
}
// Balance holds wallet balance
type Balance struct {
Coin string `json:"coin"`
CoinID string `json:"coinId"`
CoinName string `json:"coinName"`
Total float64 `json:"total,string"`
Free float64 `json:"free,string"`
Locked float64 `json:"locked,string"`
Coin string `json:"coin"`
CoinID string `json:"coinId"`
CoinName string `json:"coinName"`
Total convert.StringToFloat64 `json:"total"`
Free convert.StringToFloat64 `json:"free"`
Locked convert.StringToFloat64 `json:"locked"`
}
type orderbookResponse struct {
@@ -443,12 +418,12 @@ type WsParams struct {
// WsSpotTickerData stores ws ticker data
type WsSpotTickerData struct {
Symbol string `json:"symbol"`
Bid float64 `json:"bidPrice,string"`
Ask float64 `json:"askPrice,string"`
BidSize float64 `json:"bidQty,string"`
AskSize float64 `json:"askQty,string"`
Time bybitTimeMilliSec `json:"time"`
Symbol string `json:"symbol"`
Bid convert.StringToFloat64 `json:"bidPrice"`
Ask convert.StringToFloat64 `json:"askPrice"`
BidSize convert.StringToFloat64 `json:"bidQty"`
AskSize convert.StringToFloat64 `json:"askQty"`
Time bybitTimeMilliSec `json:"time"`
}
// WsSpotTicker stores ws ticker data
@@ -460,13 +435,13 @@ type WsSpotTicker struct {
// KlineStreamData stores ws kline stream data
type KlineStreamData struct {
StartTime bybitTimeMilliSec `json:"t"`
Symbol string `json:"s"`
ClosePrice float64 `json:"c,string"`
HighPrice float64 `json:"h,string"`
LowPrice float64 `json:"l,string"`
OpenPrice float64 `json:"o,string"`
Volume float64 `json:"v,string"`
StartTime bybitTimeMilliSec `json:"t"`
Symbol string `json:"s"`
ClosePrice convert.StringToFloat64 `json:"c"`
HighPrice convert.StringToFloat64 `json:"h"`
LowPrice convert.StringToFloat64 `json:"l"`
OpenPrice convert.StringToFloat64 `json:"o"`
Volume convert.StringToFloat64 `json:"v"`
}
// KlineStream holds the kline stream data
@@ -494,11 +469,11 @@ type WsOrderbook struct {
// WsTradeData stores ws trade data
type WsTradeData struct {
Time bybitTimeMilliSec `json:"t"`
ID string `json:"v"`
Price float64 `json:"p,string"`
Size float64 `json:"q,string"`
Side bool `json:"m"`
Time bybitTimeMilliSec `json:"t"`
ID string `json:"v"`
Price convert.StringToFloat64 `json:"p"`
Size convert.StringToFloat64 `json:"q"`
Side bool `json:"m"`
}
// WsTrade stores ws trades data
@@ -520,65 +495,65 @@ type wsAccount struct {
// Currencies stores currencies data
type Currencies struct {
Asset string `json:"a"`
Available float64 `json:"f,string"`
Locked float64 `json:"l,string"`
Asset string `json:"a"`
Available convert.StringToFloat64 `json:"f"`
Locked convert.StringToFloat64 `json:"l"`
}
// wsOrderUpdate defines websocket account order update data
type wsOrderUpdate struct {
EventType string `json:"e"`
EventTime string `json:"E"`
Symbol string `json:"s"`
ClientOrderID string `json:"c"`
Side string `json:"S"`
OrderType string `json:"o"`
TimeInForce string `json:"f"`
Quantity float64 `json:"q,string"`
Price float64 `json:"p,string"`
OrderStatus string `json:"X"`
OrderID string `json:"i"`
OpponentOrderID string `json:"M"`
LastExecutedQuantity float64 `json:"l,string"`
CumulativeFilledQuantity float64 `json:"z,string"`
LastExecutedPrice float64 `json:"L,string"`
Commission float64 `json:"n,string"`
CommissionAsset string `json:"N"`
IsNormal bool `json:"u"`
IsOnOrderBook bool `json:"w"`
IsLimitMaker bool `json:"m"`
OrderCreationTime bybitTimeMilliSecStr `json:"O"`
CumulativeQuoteTransactedQuantity float64 `json:"Z,string"`
AccountID string `json:"A"`
IsClose bool `json:"C"`
Leverage float64 `json:"v,string"`
EventType string `json:"e"`
EventTime string `json:"E"`
Symbol string `json:"s"`
ClientOrderID string `json:"c"`
Side string `json:"S"`
OrderType string `json:"o"`
TimeInForce string `json:"f"`
Quantity convert.StringToFloat64 `json:"q"`
Price convert.StringToFloat64 `json:"p"`
OrderStatus string `json:"X"`
OrderID string `json:"i"`
OpponentOrderID string `json:"M"`
LastExecutedQuantity convert.StringToFloat64 `json:"l"`
CumulativeFilledQuantity convert.StringToFloat64 `json:"z"`
LastExecutedPrice convert.StringToFloat64 `json:"L"`
Commission convert.StringToFloat64 `json:"n"`
CommissionAsset string `json:"N"`
IsNormal bool `json:"u"`
IsOnOrderBook bool `json:"w"`
IsLimitMaker bool `json:"m"`
OrderCreationTime bybitTimeMilliSecStr `json:"O"`
CumulativeQuoteTransactedQuantity convert.StringToFloat64 `json:"Z"`
AccountID string `json:"A"`
IsClose bool `json:"C"`
Leverage convert.StringToFloat64 `json:"v"`
}
// wsOrderFilled defines websocket account order filled data
type wsOrderFilled struct {
EventType string `json:"e"`
EventTime string `json:"E"`
Symbol string `json:"s"`
Quantity float64 `json:"q,string"`
Timestamp bybitTimeMilliSecStr `json:"t"`
Price float64 `json:"p,string"`
TradeID string `json:"T"`
OrderID string `json:"o"`
UserGenOrderID string `json:"c"`
OpponentOrderID string `json:"O"`
AccountID string `json:"a"`
OpponentAccountID string `json:"A"`
IsMaker bool `json:"m"`
Side string `json:"S"`
EventType string `json:"e"`
EventTime string `json:"E"`
Symbol string `json:"s"`
Quantity convert.StringToFloat64 `json:"q"`
Timestamp bybitTimeMilliSecStr `json:"t"`
Price convert.StringToFloat64 `json:"p"`
TradeID string `json:"T"`
OrderID string `json:"o"`
UserGenOrderID string `json:"c"`
OpponentOrderID string `json:"O"`
AccountID string `json:"a"`
OpponentAccountID string `json:"A"`
IsMaker bool `json:"m"`
Side string `json:"S"`
}
// WsFuturesOrderbookData stores ws futures orderbook data
type WsFuturesOrderbookData struct {
Price float64 `json:"price,string"`
Symbol string `json:"symbol"`
ID int64 `json:"id"`
Side string `json:"side"`
Size float64 `json:"size"`
Price convert.StringToFloat64 `json:"price"`
Symbol string `json:"symbol"`
ID int64 `json:"id"`
Side string `json:"side"`
Size float64 `json:"size"`
}
// WsFuturesOrderbook stores ws futures orderbook
@@ -661,32 +636,32 @@ type WsInsurance struct {
// WsTickerData stores ws ticker data
type WsTickerData struct {
ID string `json:"id"`
Symbol string `json:"symbol"`
LastPrice float64 `json:"last_price,string"`
BidPrice float64 `json:"bid1_price"`
AskPrice float64 `json:"ask1_price"`
LastDirection string `json:"last_tick_direction"`
PrevPrice24h float64 `json:"prev_price_24h,string"`
Price24hPercentChange float64 `json:"price_24h_pcnt_e6"`
Price1hPercentChange float64 `json:"price_1h_pcnt_e6"`
HighPrice24h float64 `json:"high_price_24h,string"`
LowPrice24h float64 `json:"low_price_24h,string"`
PrevPrice1h float64 `json:"prev_price_1h,string"`
MarkPrice float64 `json:"mark_price,string"`
IndexPrice float64 `json:"index_price,string"`
OpenInterest float64 `json:"open_interest"`
OpenValue float64 `json:"open_value_e8"`
TotalTurnOver float64 `json:"total_turnover_e8"`
TurnOver24h float64 `json:"turnover_24h_e8"`
TotalVolume float64 `json:"total_volume"`
Volume24h float64 `json:"volume_24h"`
FundingRate int64 `json:"funding_rate_e6"`
PredictedFundingRate float64 `json:"predicted_funding_rate_e6"`
CreatedAt time.Time `json:"created_at"`
UpdateAt time.Time `json:"updated_at"`
NextFundingAt time.Time `json:"next_funding_time"`
CountDownHour int64 `json:"countdown_hour"`
ID string `json:"id"`
Symbol string `json:"symbol"`
LastPrice convert.StringToFloat64 `json:"last_price"`
BidPrice float64 `json:"bid1_price"`
AskPrice float64 `json:"ask1_price"`
LastDirection string `json:"last_tick_direction"`
PrevPrice24h convert.StringToFloat64 `json:"prev_price_24h"`
Price24hPercentChange float64 `json:"price_24h_pcnt_e6"`
Price1hPercentChange float64 `json:"price_1h_pcnt_e6"`
HighPrice24h convert.StringToFloat64 `json:"high_price_24h"`
LowPrice24h convert.StringToFloat64 `json:"low_price_24h"`
PrevPrice1h convert.StringToFloat64 `json:"prev_price_1h"`
MarkPrice convert.StringToFloat64 `json:"mark_price"`
IndexPrice convert.StringToFloat64 `json:"index_price"`
OpenInterest float64 `json:"open_interest"`
OpenValue float64 `json:"open_value_e8"`
TotalTurnOver float64 `json:"total_turnover_e8"`
TurnOver24h float64 `json:"turnover_24h_e8"`
TotalVolume float64 `json:"total_volume"`
Volume24h float64 `json:"volume_24h"`
FundingRate int64 `json:"funding_rate_e6"`
PredictedFundingRate float64 `json:"predicted_funding_rate_e6"`
CreatedAt time.Time `json:"created_at"`
UpdateAt time.Time `json:"updated_at"`
NextFundingAt time.Time `json:"next_funding_time"`
CountDownHour int64 `json:"countdown_hour"`
}
// WsTicker stores ws ticker
@@ -708,45 +683,45 @@ type WsDeltaTicker struct {
// WsFuturesTickerData stores ws future ticker data
type WsFuturesTickerData struct {
ID string `json:"id"`
Symbol string `json:"symbol"`
SymbolName string `json:"symbol_name"`
SymbolYear int64 `json:"symbol_year"`
ContractType string `json:"contract_type"`
Coin string `json:"coin"`
QuoteSymbol string `json:"quote_symbol"`
Mode string `json:"mode"`
IsUpBorrowable int64 `json:"is_up_borrowable"`
ImportTime bybitTimeNanoSec `json:"import_time_e9"`
StartTradingTime bybitTimeNanoSec `json:"start_trading_time_e9"`
TimeToSettle bybitTimeNanoSec `json:"settle_time_e9"`
SettleFeeRate int64 `json:"settle_fee_rate_e8"`
ContractStatus string `json:"contract_status"`
SystemSubsidy int64 `json:"system_subsidy_e8"`
LastPrice float64 `json:"last_price,string"`
BidPrice float64 `json:"bid1_price"`
AskPrice float64 `json:"ask1_price"`
LastDirection string `json:"last_tick_direction"`
PrevPrice24h float64 `json:"prev_price_24h,string"`
Price24hPercentChange float64 `json:"price_24h_pcnt_e6"`
Price1hPercentChange float64 `json:"price_1h_pcnt_e6"`
HighPrice24h float64 `json:"high_price_24h,string"`
LowPrice24h float64 `json:"low_price_24h,string"`
PrevPrice1h float64 `json:"prev_price_1h,string"`
MarkPrice float64 `json:"mark_price,string"`
IndexPrice float64 `json:"index_price,string"`
OpenInterest float64 `json:"open_interest"`
OpenValue float64 `json:"open_value_e8"`
TotalTurnOver float64 `json:"total_turnover_e8"`
TurnOver24h float64 `json:"turnover_24h_e8"`
TotalVolume float64 `json:"total_volume"`
Volume24h float64 `json:"volume_24h"`
FairBasis float64 `json:"fair_basis_e8"`
FairBasisRate float64 `json:"fair_basis_rate_e8"`
BasisInYear float64 `json:"basis_in_year_e8"`
ExpectPrice float64 `json:"expect_price,string"`
CreatedAt time.Time `json:"created_at"`
UpdateAt time.Time `json:"updated_at"`
ID string `json:"id"`
Symbol string `json:"symbol"`
SymbolName string `json:"symbol_name"`
SymbolYear int64 `json:"symbol_year"`
ContractType string `json:"contract_type"`
Coin string `json:"coin"`
QuoteSymbol string `json:"quote_symbol"`
Mode string `json:"mode"`
IsUpBorrowable int64 `json:"is_up_borrowable"`
ImportTime bybitTimeNanoSec `json:"import_time_e9"`
StartTradingTime bybitTimeNanoSec `json:"start_trading_time_e9"`
TimeToSettle bybitTimeNanoSec `json:"settle_time_e9"`
SettleFeeRate int64 `json:"settle_fee_rate_e8"`
ContractStatus string `json:"contract_status"`
SystemSubsidy int64 `json:"system_subsidy_e8"`
LastPrice convert.StringToFloat64 `json:"last_price"`
BidPrice float64 `json:"bid1_price"`
AskPrice float64 `json:"ask1_price"`
LastDirection string `json:"last_tick_direction"`
PrevPrice24h convert.StringToFloat64 `json:"prev_price_24h"`
Price24hPercentChange float64 `json:"price_24h_pcnt_e6"`
Price1hPercentChange float64 `json:"price_1h_pcnt_e6"`
HighPrice24h convert.StringToFloat64 `json:"high_price_24h"`
LowPrice24h convert.StringToFloat64 `json:"low_price_24h"`
PrevPrice1h convert.StringToFloat64 `json:"prev_price_1h"`
MarkPrice convert.StringToFloat64 `json:"mark_price"`
IndexPrice convert.StringToFloat64 `json:"index_price"`
OpenInterest float64 `json:"open_interest"`
OpenValue float64 `json:"open_value_e8"`
TotalTurnOver float64 `json:"total_turnover_e8"`
TurnOver24h float64 `json:"turnover_24h_e8"`
TotalVolume float64 `json:"total_volume"`
Volume24h float64 `json:"volume_24h"`
FairBasis float64 `json:"fair_basis_e8"`
FairBasisRate float64 `json:"fair_basis_rate_e8"`
BasisInYear float64 `json:"basis_in_year_e8"`
ExpectPrice convert.StringToFloat64 `json:"expect_price"`
CreatedAt time.Time `json:"created_at"`
UpdateAt time.Time `json:"updated_at"`
}
// WsFuturesTicker stores ws future ticker
@@ -768,11 +743,11 @@ type WsDeltaFuturesTicker struct {
// WsLiquidationData stores ws liquidation data
type WsLiquidationData struct {
Symbol string `json:"symbol"`
Side string `json:"side"`
Price float64 `json:"price,string"`
Qty float64 `json:"qty"`
Timestamp bybitTimeMilliSec `json:"time"`
Symbol string `json:"symbol"`
Side string `json:"side"`
Price convert.StringToFloat64 `json:"price"`
Qty float64 `json:"qty"`
Timestamp bybitTimeMilliSec `json:"time"`
}
// WsFuturesLiquidation stores ws future liquidation
@@ -783,36 +758,36 @@ type WsFuturesLiquidation struct {
// WsFuturesPositionData stores ws future position data
type WsFuturesPositionData struct {
UserID int64 `json:"user_id"`
Symbol string `json:"symbol"`
Side string `json:"side"`
Size float64 `json:"size"`
PositionID int64 `json:"position_idx"` // present in Futures position struct only
Mode int64 `json:"mode"` // present in Futures position struct only
Isolated bool `json:"isolated"` // present in Futures position struct only
PositionValue float64 `json:"position_value,string"`
EntryPrice float64 `json:"entry_price,string"`
LiquidPrice float64 `json:"liq_price,string"`
BustPrice float64 `json:"bust_price,string"`
Leverage float64 `json:"leverage,string"`
OrderMargin float64 `json:"order_margin,string"`
PositionMargin float64 `json:"position_margin,string"`
AvailableBalance float64 `json:"available_balance,string"`
TakeProfit float64 `json:"take_profit,string"`
TakeProfitTriggerBy string `json:"tp_trigger_by"`
StopLoss float64 `json:"stop_loss,string"`
StopLossTriggerBy string `json:"sl_trigger_by"`
RealisedPNL float64 `json:"realised_pnl,string"`
TrailingStop float64 `json:"trailing_stop,string"`
TrailingActive float64 `json:"trailing_active,string"`
WalletBalance float64 `json:"wallet_balance,string"`
RiskID int64 `json:"risk_id"`
ClosingFee float64 `json:"occ_closing_fee,string"`
FundingFee float64 `json:"occ_funding_fee,string"`
AutoAddMargin int64 `json:"auto_add_margin"`
TotalPNL float64 `json:"cum_realised_pnl,string"`
Status string `json:"position_status"`
Version int64 `json:"position_seq"`
UserID int64 `json:"user_id"`
Symbol string `json:"symbol"`
Side string `json:"side"`
Size float64 `json:"size"`
PositionID int64 `json:"position_idx"` // present in Futures position struct only
Mode int64 `json:"mode"` // present in Futures position struct only
Isolated bool `json:"isolated"` // present in Futures position struct only
PositionValue convert.StringToFloat64 `json:"position_value"`
EntryPrice convert.StringToFloat64 `json:"entry_price"`
LiquidPrice convert.StringToFloat64 `json:"liq_price"`
BustPrice convert.StringToFloat64 `json:"bust_price"`
Leverage convert.StringToFloat64 `json:"leverage"`
OrderMargin convert.StringToFloat64 `json:"order_margin"`
PositionMargin convert.StringToFloat64 `json:"position_margin"`
AvailableBalance convert.StringToFloat64 `json:"available_balance"`
TakeProfit convert.StringToFloat64 `json:"take_profit"`
TakeProfitTriggerBy string `json:"tp_trigger_by"`
StopLoss convert.StringToFloat64 `json:"stop_loss"`
StopLossTriggerBy string `json:"sl_trigger_by"`
RealisedPNL convert.StringToFloat64 `json:"realised_pnl"`
TrailingStop convert.StringToFloat64 `json:"trailing_stop"`
TrailingActive convert.StringToFloat64 `json:"trailing_active"`
WalletBalance convert.StringToFloat64 `json:"wallet_balance"`
RiskID int64 `json:"risk_id"`
ClosingFee convert.StringToFloat64 `json:"occ_closing_fee"`
FundingFee convert.StringToFloat64 `json:"occ_funding_fee"`
AutoAddMargin int64 `json:"auto_add_margin"`
TotalPNL convert.StringToFloat64 `json:"cum_realised_pnl"`
Status string `json:"position_status"`
Version int64 `json:"position_seq"`
}
// WsFuturesPosition stores ws future position
@@ -824,19 +799,19 @@ type WsFuturesPosition struct {
// WsFuturesExecutionData stores ws future execution data
type WsFuturesExecutionData struct {
Symbol string `json:"symbol"`
Side string `json:"side"`
OrderID string `json:"order_id"`
ExecutionID string `json:"exec_id"`
OrderLinkID string `json:"order_link_id"`
Price float64 `json:"price,string"`
OrderQty float64 `json:"order_qty"`
ExecutionType string `json:"exec_type"`
ExecutionQty float64 `json:"exec_qty"`
ExecutionFee float64 `json:"exec_fee,string"`
LeavesQty float64 `json:"leaves_qty"`
IsMaker bool `json:"is_maker"`
Time time.Time `json:"trade_time"`
Symbol string `json:"symbol"`
Side string `json:"side"`
OrderID string `json:"order_id"`
ExecutionID string `json:"exec_id"`
OrderLinkID string `json:"order_link_id"`
Price convert.StringToFloat64 `json:"price"`
OrderQty float64 `json:"order_qty"`
ExecutionType string `json:"exec_type"`
ExecutionQty float64 `json:"exec_qty"`
ExecutionFee convert.StringToFloat64 `json:"exec_fee"`
LeavesQty float64 `json:"leaves_qty"`
IsMaker bool `json:"is_maker"`
Time time.Time `json:"trade_time"`
}
// WsFuturesExecution stores ws future execution
@@ -847,31 +822,31 @@ type WsFuturesExecution struct {
// WsOrderData stores ws order data
type WsOrderData struct {
OrderID string `json:"order_id"`
OrderLinkID string `json:"order_link_id"`
Symbol string `json:"symbol"`
Side string `json:"side"`
OrderType string `json:"order_type"`
Price float64 `json:"price,string"`
OrderQty float64 `json:"qty"`
TimeInForce string `json:"time_in_force"`
CreateType string `json:"create_type"`
CancelType string `json:"cancel_type"`
OrderStatus string `json:"order_status"`
LeavesQty float64 `json:"leaves_qty"`
CummulativeExecQty float64 `json:"cum_exec_qty"`
CummulativeExecValue float64 `json:"cum_exec_value,string"`
CummulativeExecFee float64 `json:"cum_exec_fee,string"`
TakeProfit float64 `json:"take_profit,string"`
StopLoss float64 `json:"stop_loss,string"`
TrailingStop float64 `json:"trailing_stop,string"`
TrailingActive float64 `json:"trailing_active,string"`
LastExecPrice float64 `json:"last_exec_price,string"`
ReduceOnly bool `json:"reduce_only"`
CloseOnTrigger bool `json:"close_on_trigger"`
Time time.Time `json:"timestamp"` // present in CoinMarginedFutures and Futures only
CreateTime time.Time `json:"create_time"` // present in USDTMarginedFutures only
UpdateTime time.Time `json:"update_time"` // present in USDTMarginedFutures only
OrderID string `json:"order_id"`
OrderLinkID string `json:"order_link_id"`
Symbol string `json:"symbol"`
Side string `json:"side"`
OrderType string `json:"order_type"`
Price convert.StringToFloat64 `json:"price"`
OrderQty float64 `json:"qty"`
TimeInForce string `json:"time_in_force"`
CreateType string `json:"create_type"`
CancelType string `json:"cancel_type"`
OrderStatus string `json:"order_status"`
LeavesQty float64 `json:"leaves_qty"`
CummulativeExecQty float64 `json:"cum_exec_qty"`
CummulativeExecValue convert.StringToFloat64 `json:"cum_exec_value"`
CummulativeExecFee convert.StringToFloat64 `json:"cum_exec_fee"`
TakeProfit convert.StringToFloat64 `json:"take_profit"`
StopLoss convert.StringToFloat64 `json:"stop_loss"`
TrailingStop convert.StringToFloat64 `json:"trailing_stop"`
TrailingActive convert.StringToFloat64 `json:"trailing_active"`
LastExecPrice convert.StringToFloat64 `json:"last_exec_price"`
ReduceOnly bool `json:"reduce_only"`
CloseOnTrigger bool `json:"close_on_trigger"`
Time time.Time `json:"timestamp"` // present in CoinMarginedFutures and Futures only
CreateTime time.Time `json:"create_time"` // present in USDTMarginedFutures only
UpdateTime time.Time `json:"update_time"` // present in USDTMarginedFutures only
}
// WsOrder stores ws order
@@ -882,23 +857,23 @@ type WsOrder struct {
// WsStopOrderData stores ws stop order data
type WsStopOrderData struct {
OrderID string `json:"order_id"`
OrderLinkID string `json:"order_link_id"`
UserID int64 `json:"user_id"`
Symbol string `json:"symbol"`
Side string `json:"side"`
OrderType string `json:"order_type"`
Price float64 `json:"price,string"`
OrderQty float64 `json:"qty"`
TimeInForce string `json:"time_in_force"`
CreateType string `json:"create_type"`
CancelType string `json:"cancel_type"`
OrderStatus string `json:"order_status"`
StopOrderType string `json:"stop_order_type"`
TriggerBy string `json:"trigger_by"`
TriggerPrice float64 `json:"trigger_price,string"`
Time time.Time `json:"timestamp"`
CloseOnTrigger bool `json:"close_on_trigger"`
OrderID string `json:"order_id"`
OrderLinkID string `json:"order_link_id"`
UserID int64 `json:"user_id"`
Symbol string `json:"symbol"`
Side string `json:"side"`
OrderType string `json:"order_type"`
Price convert.StringToFloat64 `json:"price"`
OrderQty float64 `json:"qty"`
TimeInForce string `json:"time_in_force"`
CreateType string `json:"create_type"`
CancelType string `json:"cancel_type"`
OrderStatus string `json:"order_status"`
StopOrderType string `json:"stop_order_type"`
TriggerBy string `json:"trigger_by"`
TriggerPrice convert.StringToFloat64 `json:"trigger_price"`
Time time.Time `json:"timestamp"`
CloseOnTrigger bool `json:"close_on_trigger"`
}
// WsFuturesStopOrder stores ws future stop order
@@ -909,23 +884,23 @@ type WsFuturesStopOrder struct {
// WsUSDTStopOrderData stores ws USDT stop order data
type WsUSDTStopOrderData struct {
OrderID string `json:"stop_order_id"`
OrderLinkID string `json:"order_link_id"`
UserID int64 `json:"user_id"`
Symbol string `json:"symbol"`
Side string `json:"side"`
OrderType string `json:"order_type"`
Price float64 `json:"price,string"`
OrderQty float64 `json:"qty"`
TimeInForce string `json:"time_in_force"`
OrderStatus string `json:"order_status"`
StopOrderType string `json:"stop_order_type"`
TriggerBy string `json:"trigger_by"`
TriggerPrice float64 `json:"trigger_price,string"`
ReduceOnly bool `json:"reduce_only"`
CloseOnTrigger bool `json:"close_on_trigger"`
CreateTime time.Time `json:"create_time"`
UpdateTime time.Time `json:"update_time"`
OrderID string `json:"stop_order_id"`
OrderLinkID string `json:"order_link_id"`
UserID int64 `json:"user_id"`
Symbol string `json:"symbol"`
Side string `json:"side"`
OrderType string `json:"order_type"`
Price convert.StringToFloat64 `json:"price"`
OrderQty float64 `json:"qty"`
TimeInForce string `json:"time_in_force"`
OrderStatus string `json:"order_status"`
StopOrderType string `json:"stop_order_type"`
TriggerBy string `json:"trigger_by"`
TriggerPrice convert.StringToFloat64 `json:"trigger_price"`
ReduceOnly bool `json:"reduce_only"`
CloseOnTrigger bool `json:"close_on_trigger"`
CreateTime time.Time `json:"create_time"`
UpdateTime time.Time `json:"update_time"`
}
// WsUSDTFuturesStopOrder stores ws USDT stop order
@@ -945,3 +920,68 @@ type WsFuturesWallet struct {
Topic string `json:"topic"`
Data []WsFuturesWalletData `json:"data"`
}
// Ticker holds ticker information
type Ticker struct {
// Spot fields
Symbol string `json:"symbol"`
TopBidPrice convert.StringToFloat64 `json:"bid1Price"`
TopBidSize convert.StringToFloat64 `json:"bid1Size"`
TopAskPrice convert.StringToFloat64 `json:"ask1Price"`
TopAskSize convert.StringToFloat64 `json:"ask1Size"`
LastPrice convert.StringToFloat64 `json:"lastPrice"`
PreviousPrice24Hr convert.StringToFloat64 `json:"prevPrice24h"`
Price24HrPcnt convert.StringToFloat64 `json:"price24hPcnt"`
HighPrice24Hr convert.StringToFloat64 `json:"highPrice24h"`
LowPrice24Hr convert.StringToFloat64 `json:"lowPrice24h"`
Turnover24Hr convert.StringToFloat64 `json:"turnover24h"`
Volume24Hr convert.StringToFloat64 `json:"volume24h"`
USDIndexPrice convert.StringToFloat64 `json:"usdIndexPrice"`
// Option fields
TopBidImpliedVolatility convert.StringToFloat64 `json:"bid1Iv"`
TopAskImpliedVolatility convert.StringToFloat64 `json:"ask1Iv"`
MarkPrice convert.StringToFloat64 `json:"markPrice"`
IndexPrice convert.StringToFloat64 `json:"indexPrice"`
MarkImpliedVolatility convert.StringToFloat64 `json:"markIv"`
UnderlyingPrice convert.StringToFloat64 `json:"underlyingPrice"`
OpenInterest convert.StringToFloat64 `json:"openInterest"`
TotalVolume convert.StringToFloat64 `json:"totalVolume"`
TotalTurnover convert.StringToFloat64 `json:"totalTurnover"`
Delta convert.StringToFloat64 `json:"delta"`
Gamma convert.StringToFloat64 `json:"gamma"`
Vega convert.StringToFloat64 `json:"vega"`
Theta convert.StringToFloat64 `json:"theta"`
PredictedDeliveryPrice convert.StringToFloat64 `json:"predictedDeliveryPrice"`
Change24h convert.StringToFloat64 `json:"change24h"`
// Inverse/linear fields
PrevPrice1h convert.StringToFloat64 `json:"prevPrice1h"`
OpenInterestValue convert.StringToFloat64 `json:"openInterestValue"`
FundingRate convert.StringToFloat64 `json:"fundingRate"`
NextFundingTime convert.StringToFloat64 `json:"nextFundingTime"`
BasisRate convert.StringToFloat64 `json:"basisRate"`
DeliveryFeeRate convert.StringToFloat64 `json:"deliveryFeeRate"`
DeliveryTime convert.StringToFloat64 `json:"deliveryTime"`
Basis convert.StringToFloat64 `json:"basis"`
}
// Fee holds fee information
type Fee struct {
BaseCoin string `json:"baseCoin"`
Symbol string `json:"symbol"`
Taker convert.StringToFloat64 `json:"takerFeeRate"`
Maker convert.StringToFloat64 `json:"makerFeeRate"`
}
// AccountFee holds account fee information
type AccountFee struct {
Category string `json:"category"`
List []Fee `json:"list"`
}
// ListOfTickers holds list of tickers
type ListOfTickers struct {
Category string `json:"category"`
List []Ticker `json:"list"`
}

View File

@@ -11,6 +11,7 @@ import (
"time"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/common/convert"
"github.com/thrasher-corp/gocryptotrader/common/crypto"
"github.com/thrasher-corp/gocryptotrader/currency"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
@@ -79,13 +80,13 @@ func (by *Bybit) GetUSDCFuturesOrderbook(ctx context.Context, symbol currency.Pa
switch data.Result[x].Side {
case sideBuy:
resp.Bids = append(resp.Bids, orderbook.Item{
Price: data.Result[x].Price,
Amount: data.Result[x].Size,
Price: data.Result[x].Price.Float64(),
Amount: data.Result[x].Size.Float64(),
})
case sideSell:
resp.Asks = append(resp.Asks, orderbook.Item{
Price: data.Result[x].Price,
Amount: data.Result[x].Size,
Price: data.Result[x].Price.Float64(),
Amount: data.Result[x].Size.Float64(),
})
default:
return nil, errInvalidSide
@@ -884,7 +885,7 @@ func (by *Bybit) GetUSDCPosition(ctx context.Context, symbol currency.Pair, cate
func (by *Bybit) SetUSDCLeverage(ctx context.Context, symbol currency.Pair, leverage float64) (float64, error) {
resp := struct {
Result struct {
Leverage float64 `json:"leverage,string"`
Leverage convert.StringToFloat64 `json:"leverage"`
} `json:"result"`
USDCError
}{}
@@ -895,7 +896,7 @@ func (by *Bybit) SetUSDCLeverage(ctx context.Context, symbol currency.Pair, leve
}
symbolValue, err := by.FormatSymbol(symbol, asset.USDCMarginedFutures)
if err != nil {
return resp.Result.Leverage, err
return 0, err
}
req["symbol"] = symbolValue
@@ -904,7 +905,8 @@ func (by *Bybit) SetUSDCLeverage(ctx context.Context, symbol currency.Pair, leve
}
req["leverage"] = strconv.FormatFloat(leverage, 'f', -1, 64)
return resp.Result.Leverage, by.SendUSDCAuthHTTPRequest(ctx, exchange.RestUSDCMargined, http.MethodPost, usdcfuturesSetLeverage, req, &resp, usdcSetLeverageRate)
return resp.Result.Leverage.Float64(),
by.SendUSDCAuthHTTPRequest(ctx, exchange.RestUSDCMargined, http.MethodPost, usdcfuturesSetLeverage, req, &resp, usdcSetLeverageRate)
}
// GetUSDCSettlementHistory gets USDC settlement history with support of last 30 days.
@@ -1014,8 +1016,8 @@ func (by *Bybit) GetUSDCLastFundingRate(ctx context.Context, symbol currency.Pai
func (by *Bybit) GetUSDCPredictedFundingRate(ctx context.Context, symbol currency.Pair) (predictedFundingRate, predictedFundingFee float64, err error) {
resp := struct {
Result struct {
PredictedFundingRate float64 `json:"predictedFundingRate,string"`
PredictedFundingFee float64 `json:"predictedFundingFee,string"`
PredictedFundingRate convert.StringToFloat64 `json:"predictedFundingRate"`
PredictedFundingFee convert.StringToFloat64 `json:"predictedFundingFee"`
} `json:"result"`
USDCError
}{}
@@ -1023,17 +1025,17 @@ func (by *Bybit) GetUSDCPredictedFundingRate(ctx context.Context, symbol currenc
req := make(map[string]interface{})
var symbolValue string
if symbol.IsEmpty() {
return resp.Result.PredictedFundingRate, resp.Result.PredictedFundingFee, errSymbolMissing
return 0, 0, errSymbolMissing
}
symbolValue, err = by.FormatSymbol(symbol, asset.USDCMarginedFutures)
if err != nil {
return resp.Result.PredictedFundingRate, resp.Result.PredictedFundingFee, err
return 0, 0, err
}
req["symbol"] = symbolValue
err = by.SendUSDCAuthHTTPRequest(ctx, exchange.RestUSDCMargined, http.MethodPost, usdcfuturesGetPredictedFundingRate, req, &resp, usdcGetPredictedFundingRate)
predictedFundingRate = resp.Result.PredictedFundingRate
predictedFundingFee = resp.Result.PredictedFundingFee
predictedFundingRate = resp.Result.PredictedFundingRate.Float64()
predictedFundingFee = resp.Result.PredictedFundingFee.Float64()
return
}

View File

@@ -301,8 +301,8 @@ func (by *Bybit) wsHandleData(respRaw []byte) error {
CurrencyPair: p,
AssetType: asset.Spot,
Exchange: by.Name,
Price: data.TradeData.Price,
Amount: data.TradeData.Size,
Price: data.TradeData.Price.Float64(),
Amount: data.TradeData.Size.Float64(),
Side: side,
TID: data.TradeData.ID,
})
@@ -320,8 +320,8 @@ func (by *Bybit) wsHandleData(respRaw []byte) error {
by.Websocket.DataHandler <- &ticker.Price{
ExchangeName: by.Name,
Bid: data.Ticker.Bid,
Ask: data.Ticker.Ask,
Bid: data.Ticker.Bid.Float64(),
Ask: data.Ticker.Ask.Float64(),
LastUpdated: data.Ticker.Time.Time(),
AssetType: asset.Spot,
Pair: p,
@@ -345,11 +345,11 @@ func (by *Bybit) wsHandleData(respRaw []byte) error {
Exchange: by.Name,
StartTime: data.Kline.StartTime.Time(),
Interval: data.Parameters.KlineType,
OpenPrice: data.Kline.OpenPrice,
ClosePrice: data.Kline.ClosePrice,
HighPrice: data.Kline.HighPrice,
LowPrice: data.Kline.LowPrice,
Volume: data.Kline.Volume,
OpenPrice: data.Kline.OpenPrice.Float64(),
ClosePrice: data.Kline.ClosePrice.Float64(),
HighPrice: data.Kline.HighPrice.Float64(),
LowPrice: data.Kline.LowPrice.Float64(),
Volume: data.Kline.Volume.Float64(),
}
return nil
default:
@@ -431,10 +431,10 @@ func (by *Bybit) wsHandleData(respRaw []byte) error {
}
by.Websocket.DataHandler <- order.Detail{
Price: data[j].Price,
Amount: data[j].Quantity,
ExecutedAmount: data[j].CumulativeFilledQuantity,
RemainingAmount: data[j].Quantity - data[j].CumulativeFilledQuantity,
Price: data[j].Price.Float64(),
Amount: data[j].Quantity.Float64(),
ExecutedAmount: data[j].CumulativeFilledQuantity.Float64(),
RemainingAmount: data[j].Quantity.Float64() - data[j].CumulativeFilledQuantity.Float64(),
Exchange: by.Name,
OrderID: data[j].OrderID,
Type: oType,
@@ -446,8 +446,8 @@ func (by *Bybit) wsHandleData(respRaw []byte) error {
ClientOrderID: data[j].ClientOrderID,
Trades: []order.TradeHistory{
{
Price: data[j].Price,
Amount: data[j].Quantity,
Price: data[j].Price.Float64(),
Amount: data[j].Quantity.Float64(),
Exchange: by.Name,
Timestamp: data[j].OrderCreationTime.Time(),
},
@@ -486,13 +486,13 @@ func (by *Bybit) wsHandleData(respRaw []byte) error {
Side: oSide,
AssetType: asset.Spot,
Pair: p,
Price: data[j].Price,
Amount: data[j].Quantity,
Price: data[j].Price.Float64(),
Amount: data[j].Quantity.Float64(),
Date: data[j].Timestamp.Time(),
Trades: []order.TradeHistory{
{
Price: data[j].Price,
Amount: data[j].Quantity,
Price: data[j].Price.Float64(),
Amount: data[j].Quantity.Float64(),
Exchange: by.Name,
Timestamp: data[j].Timestamp.Time(),
TID: data[j].TradeID,

View File

@@ -381,13 +381,16 @@ func (by *Bybit) FetchTradablePairs(ctx context.Context, a asset.Item) (currency
if err != nil {
return nil, err
}
pairs := make([]currency.Pair, len(allPairs))
pairs := make([]currency.Pair, 0, len(allPairs))
for x := range allPairs {
if allPairs[x].Status != "ONLINE" {
continue
}
pair, err = currency.NewPairFromStrings(allPairs[x].BaseCoin, "PERP")
if err != nil {
return nil, err
}
pairs[x] = pair
pairs = append(pairs, pair)
}
return pairs, nil
}
@@ -413,58 +416,62 @@ func (by *Bybit) UpdateTradablePairs(ctx context.Context, forceUpdate bool) erro
// UpdateTickers updates the ticker for all currency pairs of a given asset type
func (by *Bybit) UpdateTickers(ctx context.Context, assetType asset.Item) error {
allPairs, err := by.GetEnabledPairs(assetType)
avail, err := by.GetAvailablePairs(assetType)
if err != nil {
return err
}
enabled, err := by.GetEnabledPairs(assetType)
if err != nil {
return err
}
switch assetType {
case asset.Spot:
tick, err := by.Get24HrsChange(ctx, "")
ticks, err := by.GetTickersV5(ctx, "spot", "", "")
if err != nil {
return err
}
for p := range allPairs {
formattedPair, err := by.FormatExchangeCurrency(allPairs[p], assetType)
for x := range ticks.List {
pair, err := avail.DeriveFrom(ticks.List[x].Symbol)
if err != nil {
// These symbols below do not have a spot market but are in fact
// perpetuals.
if ticks.List[x].Symbol == "ZECUSDT" || ticks.List[x].Symbol == "DASHUSDT" {
continue
}
return err
}
for y := range tick {
if tick[y].Symbol != formattedPair.String() {
continue
}
if !enabled.Contains(pair, true) {
continue
}
cp, err := by.extractCurrencyPair(tick[y].Symbol, assetType)
if err != nil {
return err
}
err = ticker.ProcessTicker(&ticker.Price{
Last: tick[y].LastPrice,
High: tick[y].HighPrice,
Low: tick[y].LowPrice,
Bid: tick[y].BestBidPrice,
Ask: tick[y].BestAskPrice,
Volume: tick[y].Volume,
QuoteVolume: tick[y].QuoteVolume,
Open: tick[y].OpenPrice,
Pair: cp,
LastUpdated: tick[y].Time,
ExchangeName: by.Name,
AssetType: assetType})
if err != nil {
return err
}
err = ticker.ProcessTicker(&ticker.Price{
Last: ticks.List[x].LastPrice.Float64(),
High: ticks.List[x].HighPrice24Hr.Float64(),
Low: ticks.List[x].LowPrice24Hr.Float64(),
Bid: ticks.List[x].TopBidPrice.Float64(),
BidSize: ticks.List[x].TopBidSize.Float64(),
Ask: ticks.List[x].TopAskPrice.Float64(),
AskSize: ticks.List[x].TopAskSize.Float64(),
Volume: ticks.List[x].Volume24Hr.Float64(),
Pair: pair,
ExchangeName: by.Name,
AssetType: assetType})
if err != nil {
return err
}
}
case asset.CoinMarginedFutures, asset.USDTMarginedFutures, asset.Futures:
tick, err := by.GetFuturesSymbolPriceTicker(ctx, currency.Pair{})
if err != nil {
return err
}
for p := range allPairs {
formattedPair, err := by.FormatExchangeCurrency(allPairs[p], assetType)
for p := range enabled {
formattedPair, err := by.FormatExchangeCurrency(enabled[p], assetType)
if err != nil {
return err
}
@@ -478,11 +485,11 @@ func (by *Bybit) UpdateTickers(ctx context.Context, assetType asset.Item) error
return err
}
err = ticker.ProcessTicker(&ticker.Price{
Last: tick[y].LastPrice,
High: tick[y].HighPrice24h,
Low: tick[y].LowPrice24h,
Bid: tick[y].BidPrice,
Ask: tick[y].AskPrice,
Last: tick[y].LastPrice.Float64(),
High: tick[y].HighPrice24h.Float64(),
Low: tick[y].LowPrice24h.Float64(),
Bid: tick[y].BidPrice.Float64(),
Ask: tick[y].AskPrice.Float64(),
Volume: tick[y].Volume24h,
Open: tick[y].OpenValue.Float64(),
Pair: cp,
@@ -493,10 +500,9 @@ func (by *Bybit) UpdateTickers(ctx context.Context, assetType asset.Item) error
}
}
}
case asset.USDCMarginedFutures:
for p := range allPairs {
formattedPair, err := by.FormatExchangeCurrency(allPairs[p], assetType)
for x := range enabled {
formattedPair, err := by.FormatExchangeCurrency(enabled[x], assetType)
if err != nil {
return err
}
@@ -511,12 +517,12 @@ func (by *Bybit) UpdateTickers(ctx context.Context, assetType asset.Item) error
return err
}
err = ticker.ProcessTicker(&ticker.Price{
Last: tick.LastPrice,
High: tick.High24h,
Low: tick.Low24h,
Bid: tick.Bid,
Ask: tick.Ask,
Volume: tick.Volume24h,
Last: tick.LastPrice.Float64(),
High: tick.High24h.Float64(),
Low: tick.Low24h.Float64(),
Bid: tick.Bid.Float64(),
Ask: tick.Ask.Float64(),
Volume: tick.Volume24h.Float64(),
Pair: cp,
ExchangeName: by.Name,
AssetType: assetType})
@@ -524,11 +530,9 @@ func (by *Bybit) UpdateTickers(ctx context.Context, assetType asset.Item) error
return err
}
}
default:
return fmt.Errorf("%s %w", assetType, asset.ErrNotSupported)
}
return nil
}
@@ -552,16 +556,16 @@ func (by *Bybit) UpdateTicker(ctx context.Context, p currency.Pair, assetType as
return nil, err
}
err = ticker.ProcessTicker(&ticker.Price{
Last: tick[y].LastPrice,
High: tick[y].HighPrice,
Low: tick[y].LowPrice,
Bid: tick[y].BestBidPrice,
Ask: tick[y].BestAskPrice,
Volume: tick[y].Volume,
QuoteVolume: tick[y].QuoteVolume,
Open: tick[y].OpenPrice,
Last: tick[y].LastPrice.Float64(),
High: tick[y].HighPrice.Float64(),
Low: tick[y].LowPrice.Float64(),
Bid: tick[y].BestBidPrice.Float64(),
Ask: tick[y].BestAskPrice.Float64(),
Volume: tick[y].Volume.Float64(),
QuoteVolume: tick[y].QuoteVolume.Float64(),
Open: tick[y].OpenPrice.Float64(),
Pair: cp,
LastUpdated: tick[y].Time,
LastUpdated: tick[y].Time.Time(),
ExchangeName: by.Name,
AssetType: assetType})
if err != nil {
@@ -581,11 +585,11 @@ func (by *Bybit) UpdateTicker(ctx context.Context, p currency.Pair, assetType as
return nil, err
}
err = ticker.ProcessTicker(&ticker.Price{
Last: tick[y].LastPrice,
High: tick[y].HighPrice24h,
Low: tick[y].LowPrice24h,
Bid: tick[y].BidPrice,
Ask: tick[y].AskPrice,
Last: tick[y].LastPrice.Float64(),
High: tick[y].HighPrice24h.Float64(),
Low: tick[y].LowPrice24h.Float64(),
Bid: tick[y].BidPrice.Float64(),
Ask: tick[y].AskPrice.Float64(),
Volume: tick[y].Volume24h,
Open: tick[y].OpenValue.Float64(),
Pair: cp,
@@ -607,12 +611,12 @@ func (by *Bybit) UpdateTicker(ctx context.Context, p currency.Pair, assetType as
return nil, err
}
err = ticker.ProcessTicker(&ticker.Price{
Last: tick.LastPrice,
High: tick.High24h,
Low: tick.Low24h,
Bid: tick.Bid,
Ask: tick.Ask,
Volume: tick.Volume24h,
Last: tick.LastPrice.Float64(),
High: tick.High24h.Float64(),
Low: tick.Low24h.Float64(),
Bid: tick.Bid.Float64(),
Ask: tick.Ask.Float64(),
Volume: tick.Volume24h.Float64(),
Pair: cp,
ExchangeName: by.Name,
AssetType: assetType})
@@ -719,9 +723,9 @@ func (by *Bybit) UpdateAccountInfo(ctx context.Context, assetType asset.Item) (a
for i := range balances {
currencyBalance[i] = account.Balance{
Currency: currency.NewCode(balances[i].CoinName),
Total: balances[i].Total,
Hold: balances[i].Locked,
Free: balances[i].Total - balances[i].Locked,
Total: balances[i].Total.Float64(),
Hold: balances[i].Locked.Float64(),
Free: balances[i].Total.Float64() - balances[i].Locked.Float64(),
}
}
@@ -756,9 +760,9 @@ func (by *Bybit) UpdateAccountInfo(ctx context.Context, assetType asset.Item) (a
acc.Currencies = []account.Balance{
{
Currency: currency.USD,
Total: balance.WalletBalance,
Hold: balance.WalletBalance - balance.AvailableBalance,
Free: balance.AvailableBalance,
Total: balance.WalletBalance.Float64(),
Hold: balance.WalletBalance.Float64() - balance.AvailableBalance.Float64(),
Free: balance.AvailableBalance.Float64(),
},
}
@@ -813,7 +817,7 @@ func (by *Bybit) GetWithdrawalsHistory(ctx context.Context, c currency.Code, a a
Status: w[i].Status,
TransferID: strconv.FormatInt(w[i].ID, 10),
Currency: w[i].Coin,
Amount: w[i].Amount,
Amount: w[i].Amount.Float64(),
Fee: w[i].Fee,
CryptoToAddress: w[i].Address,
CryptoTxID: w[i].TxID,
@@ -898,8 +902,8 @@ func (by *Bybit) GetRecentTrades(ctx context.Context, p currency.Pair, assetType
Exchange: by.Name,
CurrencyPair: p,
AssetType: assetType,
Price: tradeData[i].OrderPrice,
Amount: tradeData[i].OrderQty,
Price: tradeData[i].OrderPrice.Float64(),
Amount: tradeData[i].OrderQty.Float64(),
Timestamp: tradeData[i].Timestamp.Time(),
})
}
@@ -1230,18 +1234,18 @@ func (by *Bybit) GetOrderInfo(ctx context.Context, orderID string, pair currency
}
return order.Detail{
Amount: resp.Quantity,
Amount: resp.Quantity.Float64(),
Exchange: by.Name,
OrderID: resp.OrderID,
ClientOrderID: resp.OrderLinkID,
Side: getSide(resp.Side),
Type: getTradeType(resp.TradeType),
Pair: pair,
Cost: resp.CummulativeQuoteQty,
Cost: resp.CummulativeQuoteQty.Float64(),
AssetType: assetType,
Status: getOrderStatus(resp.Status),
Price: resp.Price,
ExecutedAmount: resp.ExecutedQty,
Price: resp.Price.Float64(),
ExecutedAmount: resp.ExecutedQty.Float64(),
Date: resp.Time.Time(),
LastUpdated: resp.UpdateTime.Time(),
}, nil
@@ -1264,7 +1268,7 @@ func (by *Bybit) GetOrderInfo(ctx context.Context, orderID string, pair currency
Side: getSide(resp[0].Side),
Type: getTradeType(resp[0].OrderType),
Pair: pair,
Cost: resp[0].CumulativeQty,
Cost: resp[0].CumulativeQty.Float64(),
AssetType: assetType,
Status: getOrderStatus(resp[0].OrderStatus),
Price: resp[0].Price,
@@ -1291,7 +1295,7 @@ func (by *Bybit) GetOrderInfo(ctx context.Context, orderID string, pair currency
Side: getSide(resp[0].Side),
Type: getTradeType(resp[0].OrderType),
Pair: pair,
Cost: resp[0].CumulativeQty,
Cost: resp[0].CumulativeQty.Float64(),
AssetType: assetType,
Status: getOrderStatus(resp[0].OrderStatus),
Price: resp[0].Price,
@@ -1318,7 +1322,7 @@ func (by *Bybit) GetOrderInfo(ctx context.Context, orderID string, pair currency
Side: getSide(resp[0].Side),
Type: getTradeType(resp[0].OrderType),
Pair: pair,
Cost: resp[0].CumulativeQty,
Cost: resp[0].CumulativeQty.Float64(),
AssetType: assetType,
Status: getOrderStatus(resp[0].OrderStatus),
Price: resp[0].Price,
@@ -1338,18 +1342,18 @@ func (by *Bybit) GetOrderInfo(ctx context.Context, orderID string, pair currency
}
return order.Detail{
Amount: resp[0].Qty,
Amount: resp[0].Qty.Float64(),
Exchange: by.Name,
OrderID: resp[0].ID,
ClientOrderID: resp[0].OrderLinkID,
Side: getSide(resp[0].Side),
Type: getTradeType(resp[0].OrderType),
Pair: pair,
Cost: resp[0].TotalOrderValue,
Cost: resp[0].TotalOrderValue.Float64(),
AssetType: assetType,
Status: getOrderStatus(resp[0].OrderStatus),
Price: resp[0].Price,
ExecutedAmount: resp[0].TotalFilledQty,
Price: resp[0].Price.Float64(),
ExecutedAmount: resp[0].TotalFilledQty.Float64(),
Date: resp[0].CreatedAt.Time(),
}, nil
@@ -1453,14 +1457,14 @@ func (by *Bybit) GetActiveOrders(ctx context.Context, req *order.GetOrdersReques
for i := range req.Pairs {
if req.Pairs[i].String() == openOrders[x].SymbolName {
orders = append(orders, order.Detail{
Amount: openOrders[x].Quantity,
Amount: openOrders[x].Quantity.Float64(),
Date: openOrders[x].Time.Time(),
Exchange: by.Name,
OrderID: openOrders[x].OrderID,
ClientOrderID: openOrders[x].OrderLinkID,
Side: getSide(openOrders[x].Side),
Type: getTradeType(openOrders[x].TradeType),
Price: openOrders[x].Price,
Price: openOrders[x].Price.Float64(),
Status: getOrderStatus(openOrders[x].Status),
Pair: req.Pairs[i],
AssetType: req.AssetType,
@@ -1557,11 +1561,11 @@ func (by *Bybit) GetActiveOrders(ctx context.Context, req *order.GetOrdersReques
for i := range req.Pairs {
if req.Pairs[i].String() == openOrders[x].Symbol {
orders = append(orders, order.Detail{
Price: openOrders[x].Price,
Amount: openOrders[x].Qty,
ExecutedAmount: openOrders[x].TotalFilledQty,
RemainingAmount: openOrders[x].Qty - openOrders[x].TotalFilledQty,
Fee: openOrders[x].TotalFee,
Price: openOrders[x].Price.Float64(),
Amount: openOrders[x].Qty.Float64(),
ExecutedAmount: openOrders[x].TotalFilledQty.Float64(),
RemainingAmount: openOrders[x].Qty.Float64() - openOrders[x].TotalFilledQty.Float64(),
Fee: openOrders[x].TotalFee.Float64(),
Exchange: by.Name,
OrderID: openOrders[x].ID,
ClientOrderID: openOrders[x].OrderLinkID,
@@ -1610,17 +1614,17 @@ func (by *Bybit) GetOrderHistory(ctx context.Context, req *order.GetOrdersReques
return nil, err
}
detail := order.Detail{
Amount: resp[i].Quantity,
ExecutedAmount: resp[i].ExecutedQty,
RemainingAmount: resp[i].Quantity - resp[i].ExecutedQty,
Cost: resp[i].CummulativeQuoteQty,
Amount: resp[i].Quantity.Float64(),
ExecutedAmount: resp[i].ExecutedQty.Float64(),
RemainingAmount: resp[i].Quantity.Float64() - resp[i].ExecutedQty.Float64(),
Cost: resp[i].CummulativeQuoteQty.Float64(),
Date: resp[i].Time.Time(),
LastUpdated: resp[i].UpdateTime.Time(),
Exchange: by.Name,
OrderID: resp[i].OrderID,
Side: side,
Type: getTradeType(resp[i].TradeType),
Price: resp[i].Price,
Price: resp[i].Price.Float64(),
Pair: pair,
Status: getOrderStatus(resp[i].Status),
}
@@ -1731,16 +1735,16 @@ func (by *Bybit) GetOrderHistory(ctx context.Context, req *order.GetOrdersReques
return nil, err
}
detail := order.Detail{
Amount: resp[i].Qty,
ExecutedAmount: resp[i].TotalFilledQty,
RemainingAmount: resp[i].LeavesQty,
Amount: resp[i].Qty.Float64(),
ExecutedAmount: resp[i].TotalFilledQty.Float64(),
RemainingAmount: resp[i].LeavesQty.Float64(),
Date: resp[i].CreatedAt.Time(),
LastUpdated: resp[i].UpdatedAt.Time(),
Exchange: by.Name,
OrderID: resp[i].ID,
Side: getSide(resp[i].Side),
Type: orderType,
Price: resp[i].Price,
Price: resp[i].Price.Float64(),
Pair: pair,
Status: orderStatus,
}
@@ -1879,11 +1883,11 @@ func (by *Bybit) GetHistoricCandles(ctx context.Context, pair currency.Pair, a a
for x := range candles {
timeSeries[x] = kline.Candle{
Time: time.Unix(candles[x].OpenTime, 0),
Open: candles[x].Open,
High: candles[x].High,
Low: candles[x].Low,
Close: candles[x].Close,
Volume: candles[x].Volume,
Open: candles[x].Open.Float64(),
High: candles[x].High.Float64(),
Low: candles[x].Low.Float64(),
Close: candles[x].Close.Float64(),
Volume: candles[x].Volume.Float64(),
}
}
case asset.USDTMarginedFutures:
@@ -1923,11 +1927,11 @@ func (by *Bybit) GetHistoricCandles(ctx context.Context, pair currency.Pair, a a
for x := range candles {
timeSeries[x] = kline.Candle{
Time: candles[x].OpenTime.Time(),
Open: candles[x].Open,
High: candles[x].High,
Low: candles[x].Low,
Close: candles[x].Close,
Volume: candles[x].Volume,
Open: candles[x].Open.Float64(),
High: candles[x].High.Float64(),
Low: candles[x].Low.Float64(),
Close: candles[x].Close.Float64(),
Volume: candles[x].Volume.Float64(),
}
}
default:
@@ -1982,11 +1986,11 @@ func (by *Bybit) GetHistoricCandlesExtended(ctx context.Context, pair currency.P
for i := range candles {
timeSeries = append(timeSeries, kline.Candle{
Time: time.Unix(candles[i].OpenTime, 0),
Open: candles[i].Open,
High: candles[i].High,
Low: candles[i].Low,
Close: candles[i].Close,
Volume: candles[i].Volume,
Open: candles[i].Open.Float64(),
High: candles[i].High.Float64(),
Low: candles[i].Low.Float64(),
Close: candles[i].Close.Float64(),
Volume: candles[i].Volume.Float64(),
})
}
case asset.USDTMarginedFutures:
@@ -2024,11 +2028,11 @@ func (by *Bybit) GetHistoricCandlesExtended(ctx context.Context, pair currency.P
for x := range candles {
timeSeries = append(timeSeries, kline.Candle{
Time: candles[x].OpenTime.Time(),
Open: candles[x].Open,
High: candles[x].High,
Low: candles[x].Low,
Close: candles[x].Close,
Volume: candles[x].Volume,
Open: candles[x].Open.Float64(),
High: candles[x].High.Float64(),
Low: candles[x].Low.Float64(),
Close: candles[x].Close.Float64(),
Volume: candles[x].Volume.Float64(),
})
}
default:
@@ -2064,3 +2068,46 @@ func (by *Bybit) extractCurrencyPair(symbol string, item asset.Item) (currency.P
}
return pairs.DeriveFrom(symbol)
}
// UpdateOrderExecutionLimits sets exchange executions for a required asset type
func (by *Bybit) UpdateOrderExecutionLimits(ctx context.Context, a asset.Item) error {
avail, err := by.GetAvailablePairs(a)
if err != nil {
return err
}
var limits []order.MinMaxLevel
switch a {
case asset.Spot:
var pairsData []PairData
pairsData, err = by.GetAllSpotPairs(ctx)
if err != nil {
return err
}
limits = make([]order.MinMaxLevel, 0, len(pairsData))
for x := range pairsData {
var pair currency.Pair
pair, err = avail.DeriveFrom(pairsData[x].Name)
if err != nil {
return err
}
limits = append(limits, order.MinMaxLevel{
Asset: a,
Pair: pair,
AmountStepIncrementSize: pairsData[x].BasePrecision.Float64(),
QuoteStepIncrementSize: pairsData[x].QuotePrecision.Float64(),
MinimumBaseAmount: pairsData[x].MinTradeQuantity.Float64(),
MaximumBaseAmount: pairsData[x].MaxTradeQuantity.Float64(),
MinimumQuoteAmount: pairsData[x].MinTradeAmount.Float64(),
MaximumQuoteAmount: pairsData[x].MaxTradeAmount.Float64(),
PriceStepIncrementSize: pairsData[x].MinPricePrecision.Float64(),
})
}
default:
// TODO: Add in other assets
return fmt.Errorf("%s %w", a, asset.ErrNotSupported)
}
return by.LoadLimits(limits)
}

View File

@@ -389,13 +389,13 @@ func (by *Bybit) wsCoinHandleData(respRaw []byte) error {
by.Websocket.DataHandler <- &ticker.Price{
ExchangeName: by.Name,
Last: response.Ticker.LastPrice,
High: response.Ticker.HighPrice24h,
Low: response.Ticker.LowPrice24h,
Last: response.Ticker.LastPrice.Float64(),
High: response.Ticker.HighPrice24h.Float64(),
Low: response.Ticker.LowPrice24h.Float64(),
Bid: response.Ticker.BidPrice,
Ask: response.Ticker.AskPrice,
Volume: response.Ticker.Volume24h,
Close: response.Ticker.PrevPrice24h,
Close: response.Ticker.PrevPrice24h.Float64(),
LastUpdated: response.Ticker.UpdateAt,
AssetType: asset.CoinMarginedFutures,
Pair: p,
@@ -418,13 +418,13 @@ func (by *Bybit) wsCoinHandleData(respRaw []byte) error {
by.Websocket.DataHandler <- &ticker.Price{
ExchangeName: by.Name,
Last: response.Data.Delete[x].LastPrice,
High: response.Data.Delete[x].HighPrice24h,
Low: response.Data.Delete[x].LowPrice24h,
Last: response.Data.Delete[x].LastPrice.Float64(),
High: response.Data.Delete[x].HighPrice24h.Float64(),
Low: response.Data.Delete[x].LowPrice24h.Float64(),
Bid: response.Data.Delete[x].BidPrice,
Ask: response.Data.Delete[x].AskPrice,
Volume: response.Data.Delete[x].Volume24h,
Close: response.Data.Delete[x].PrevPrice24h,
Close: response.Data.Delete[x].PrevPrice24h.Float64(),
LastUpdated: response.Data.Delete[x].UpdateAt,
AssetType: asset.CoinMarginedFutures,
Pair: p,
@@ -442,13 +442,13 @@ func (by *Bybit) wsCoinHandleData(respRaw []byte) error {
by.Websocket.DataHandler <- &ticker.Price{
ExchangeName: by.Name,
Last: response.Data.Update[x].LastPrice,
High: response.Data.Update[x].HighPrice24h,
Low: response.Data.Update[x].LowPrice24h,
Last: response.Data.Update[x].LastPrice.Float64(),
High: response.Data.Update[x].HighPrice24h.Float64(),
Low: response.Data.Update[x].LowPrice24h.Float64(),
Bid: response.Data.Update[x].BidPrice,
Ask: response.Data.Update[x].AskPrice,
Volume: response.Data.Update[x].Volume24h,
Close: response.Data.Update[x].PrevPrice24h,
Close: response.Data.Update[x].PrevPrice24h.Float64(),
LastUpdated: response.Data.Update[x].UpdateAt,
AssetType: asset.CoinMarginedFutures,
Pair: p,
@@ -466,13 +466,13 @@ func (by *Bybit) wsCoinHandleData(respRaw []byte) error {
by.Websocket.DataHandler <- &ticker.Price{
ExchangeName: by.Name,
Last: response.Data.Insert[x].LastPrice,
High: response.Data.Insert[x].HighPrice24h,
Low: response.Data.Insert[x].LowPrice24h,
Last: response.Data.Insert[x].LastPrice.Float64(),
High: response.Data.Insert[x].HighPrice24h.Float64(),
Low: response.Data.Insert[x].LowPrice24h.Float64(),
Bid: response.Data.Insert[x].BidPrice,
Ask: response.Data.Insert[x].AskPrice,
Volume: response.Data.Insert[x].Volume24h,
Close: response.Data.Insert[x].PrevPrice24h,
Close: response.Data.Insert[x].PrevPrice24h.Float64(),
LastUpdated: response.Data.Insert[x].UpdateAt,
AssetType: asset.CoinMarginedFutures,
Pair: p,
@@ -540,13 +540,13 @@ func (by *Bybit) wsCoinHandleData(respRaw []byte) error {
OrderID: response.Data[i].OrderID,
AssetType: asset.CoinMarginedFutures,
Pair: p,
Price: response.Data[i].Price,
Price: response.Data[i].Price.Float64(),
Amount: response.Data[i].OrderQty,
Side: oSide,
Status: oStatus,
Trades: []order.TradeHistory{
{
Price: response.Data[i].Price,
Price: response.Data[i].Price.Float64(),
Amount: response.Data[i].OrderQty,
Exchange: by.Name,
Side: oSide,
@@ -598,7 +598,7 @@ func (by *Bybit) wsCoinHandleData(respRaw []byte) error {
}
}
by.Websocket.DataHandler <- &order.Detail{
Price: response.Data[x].Price,
Price: response.Data[x].Price.Float64(),
Amount: response.Data[x].OrderQty,
Exchange: by.Name,
OrderID: response.Data[x].OrderID,
@@ -610,7 +610,7 @@ func (by *Bybit) wsCoinHandleData(respRaw []byte) error {
Pair: p,
Trades: []order.TradeHistory{
{
Price: response.Data[x].Price,
Price: response.Data[x].Price.Float64(),
Amount: response.Data[x].OrderQty,
Exchange: by.Name,
Side: oSide,
@@ -660,7 +660,7 @@ func (by *Bybit) wsCoinHandleData(respRaw []byte) error {
}
}
by.Websocket.DataHandler <- &order.Detail{
Price: response.Data[x].Price,
Price: response.Data[x].Price.Float64(),
Amount: response.Data[x].OrderQty,
Exchange: by.Name,
OrderID: response.Data[x].OrderID,
@@ -673,7 +673,7 @@ func (by *Bybit) wsCoinHandleData(respRaw []byte) error {
Pair: p,
Trades: []order.TradeHistory{
{
Price: response.Data[x].Price,
Price: response.Data[x].Price.Float64(),
Amount: response.Data[x].OrderQty,
Exchange: by.Name,
Side: oSide,
@@ -709,7 +709,7 @@ func (by *Bybit) processOrderbook(data []WsFuturesOrderbookData, action string,
var book orderbook.Base
for i := range data {
item := orderbook.Item{
Price: data[i].Price,
Price: data[i].Price.Float64(),
Amount: data[i].Size,
ID: data[i].ID,
}
@@ -741,7 +741,7 @@ func (by *Bybit) processOrderbook(data []WsFuturesOrderbookData, action string,
var asks, bids []orderbook.Item
for i := range data {
item := orderbook.Item{
Price: data[i].Price,
Price: data[i].Price.Float64(),
Amount: data[i].Size,
ID: data[i].ID,
}

View File

@@ -334,13 +334,13 @@ func (by *Bybit) wsFuturesHandleData(respRaw []byte) error {
by.Websocket.DataHandler <- &ticker.Price{
ExchangeName: by.Name,
Last: response.Ticker.LastPrice,
High: response.Ticker.HighPrice24h,
Low: response.Ticker.LowPrice24h,
Last: response.Ticker.LastPrice.Float64(),
High: response.Ticker.HighPrice24h.Float64(),
Low: response.Ticker.LowPrice24h.Float64(),
Bid: response.Ticker.BidPrice,
Ask: response.Ticker.AskPrice,
Volume: response.Ticker.Volume24h,
Close: response.Ticker.PrevPrice24h,
Close: response.Ticker.PrevPrice24h.Float64(),
LastUpdated: response.Ticker.UpdateAt,
AssetType: asset.Futures,
Pair: p,
@@ -363,13 +363,13 @@ func (by *Bybit) wsFuturesHandleData(respRaw []byte) error {
by.Websocket.DataHandler <- &ticker.Price{
ExchangeName: by.Name,
Last: response.Data.Delete[x].LastPrice,
High: response.Data.Delete[x].HighPrice24h,
Low: response.Data.Delete[x].LowPrice24h,
Last: response.Data.Delete[x].LastPrice.Float64(),
High: response.Data.Delete[x].HighPrice24h.Float64(),
Low: response.Data.Delete[x].LowPrice24h.Float64(),
Bid: response.Data.Delete[x].BidPrice,
Ask: response.Data.Delete[x].AskPrice,
Volume: response.Data.Delete[x].Volume24h,
Close: response.Data.Delete[x].PrevPrice24h,
Close: response.Data.Delete[x].PrevPrice24h.Float64(),
LastUpdated: response.Data.Delete[x].UpdateAt,
AssetType: asset.Futures,
Pair: p,
@@ -387,13 +387,13 @@ func (by *Bybit) wsFuturesHandleData(respRaw []byte) error {
by.Websocket.DataHandler <- &ticker.Price{
ExchangeName: by.Name,
Last: response.Data.Update[x].LastPrice,
High: response.Data.Update[x].HighPrice24h,
Low: response.Data.Update[x].LowPrice24h,
Last: response.Data.Update[x].LastPrice.Float64(),
High: response.Data.Update[x].HighPrice24h.Float64(),
Low: response.Data.Update[x].LowPrice24h.Float64(),
Bid: response.Data.Update[x].BidPrice,
Ask: response.Data.Update[x].AskPrice,
Volume: response.Data.Update[x].Volume24h,
Close: response.Data.Update[x].PrevPrice24h,
Close: response.Data.Update[x].PrevPrice24h.Float64(),
LastUpdated: response.Data.Update[x].UpdateAt,
AssetType: asset.Futures,
Pair: p,
@@ -411,13 +411,13 @@ func (by *Bybit) wsFuturesHandleData(respRaw []byte) error {
by.Websocket.DataHandler <- &ticker.Price{
ExchangeName: by.Name,
Last: response.Data.Insert[x].LastPrice,
High: response.Data.Insert[x].HighPrice24h,
Low: response.Data.Insert[x].LowPrice24h,
Last: response.Data.Insert[x].LastPrice.Float64(),
High: response.Data.Insert[x].HighPrice24h.Float64(),
Low: response.Data.Insert[x].LowPrice24h.Float64(),
Bid: response.Data.Insert[x].BidPrice,
Ask: response.Data.Insert[x].AskPrice,
Volume: response.Data.Insert[x].Volume24h,
Close: response.Data.Insert[x].PrevPrice24h,
Close: response.Data.Insert[x].PrevPrice24h.Float64(),
LastUpdated: response.Data.Insert[x].UpdateAt,
AssetType: asset.Futures,
Pair: p,
@@ -485,13 +485,13 @@ func (by *Bybit) wsFuturesHandleData(respRaw []byte) error {
OrderID: response.Data[i].OrderID,
AssetType: asset.Futures,
Pair: p,
Price: response.Data[i].Price,
Price: response.Data[i].Price.Float64(),
Amount: response.Data[i].OrderQty,
Side: oSide,
Status: oStatus,
Trades: []order.TradeHistory{
{
Price: response.Data[i].Price,
Price: response.Data[i].Price.Float64(),
Amount: response.Data[i].OrderQty,
Exchange: by.Name,
Side: oSide,
@@ -541,7 +541,7 @@ func (by *Bybit) wsFuturesHandleData(respRaw []byte) error {
}
}
by.Websocket.DataHandler <- &order.Detail{
Price: response.Data[x].Price,
Price: response.Data[x].Price.Float64(),
Amount: response.Data[x].OrderQty,
Exchange: by.Name,
OrderID: response.Data[x].OrderID,
@@ -553,7 +553,7 @@ func (by *Bybit) wsFuturesHandleData(respRaw []byte) error {
Pair: p,
Trades: []order.TradeHistory{
{
Price: response.Data[x].Price,
Price: response.Data[x].Price.Float64(),
Amount: response.Data[x].OrderQty,
Exchange: by.Name,
Side: oSide,
@@ -603,7 +603,7 @@ func (by *Bybit) wsFuturesHandleData(respRaw []byte) error {
}
}
by.Websocket.DataHandler <- &order.Detail{
Price: response.Data[x].Price,
Price: response.Data[x].Price.Float64(),
Amount: response.Data[x].OrderQty,
Exchange: by.Name,
OrderID: response.Data[x].OrderID,
@@ -616,7 +616,7 @@ func (by *Bybit) wsFuturesHandleData(respRaw []byte) error {
Pair: p,
Trades: []order.TradeHistory{
{
Price: response.Data[x].Price,
Price: response.Data[x].Price.Float64(),
Amount: response.Data[x].OrderQty,
Exchange: by.Name,
Side: oSide,

View File

@@ -340,13 +340,13 @@ func (by *Bybit) wsUSDTHandleData(respRaw []byte) error {
by.Websocket.DataHandler <- &ticker.Price{
ExchangeName: by.Name,
Last: response.Ticker.LastPrice,
High: response.Ticker.HighPrice24h,
Low: response.Ticker.LowPrice24h,
Last: response.Ticker.LastPrice.Float64(),
High: response.Ticker.HighPrice24h.Float64(),
Low: response.Ticker.LowPrice24h.Float64(),
Bid: response.Ticker.BidPrice,
Ask: response.Ticker.AskPrice,
Volume: response.Ticker.Volume24h,
Close: response.Ticker.PrevPrice24h,
Close: response.Ticker.PrevPrice24h.Float64(),
LastUpdated: response.Ticker.UpdateAt,
AssetType: asset.USDTMarginedFutures,
Pair: p,
@@ -369,13 +369,13 @@ func (by *Bybit) wsUSDTHandleData(respRaw []byte) error {
by.Websocket.DataHandler <- &ticker.Price{
ExchangeName: by.Name,
Last: response.Data.Delete[x].LastPrice,
High: response.Data.Delete[x].HighPrice24h,
Low: response.Data.Delete[x].LowPrice24h,
Last: response.Data.Delete[x].LastPrice.Float64(),
High: response.Data.Delete[x].HighPrice24h.Float64(),
Low: response.Data.Delete[x].LowPrice24h.Float64(),
Bid: response.Data.Delete[x].BidPrice,
Ask: response.Data.Delete[x].AskPrice,
Volume: response.Data.Delete[x].Volume24h,
Close: response.Data.Delete[x].PrevPrice24h,
Close: response.Data.Delete[x].PrevPrice24h.Float64(),
LastUpdated: response.Data.Delete[x].UpdateAt,
AssetType: asset.USDTMarginedFutures,
Pair: p,
@@ -393,13 +393,13 @@ func (by *Bybit) wsUSDTHandleData(respRaw []byte) error {
by.Websocket.DataHandler <- &ticker.Price{
ExchangeName: by.Name,
Last: response.Data.Update[x].LastPrice,
High: response.Data.Update[x].HighPrice24h,
Low: response.Data.Update[x].LowPrice24h,
Last: response.Data.Update[x].LastPrice.Float64(),
High: response.Data.Update[x].HighPrice24h.Float64(),
Low: response.Data.Update[x].LowPrice24h.Float64(),
Bid: response.Data.Update[x].BidPrice,
Ask: response.Data.Update[x].AskPrice,
Volume: response.Data.Update[x].Volume24h,
Close: response.Data.Update[x].PrevPrice24h,
Close: response.Data.Update[x].PrevPrice24h.Float64(),
LastUpdated: response.Data.Update[x].UpdateAt,
AssetType: asset.USDTMarginedFutures,
Pair: p,
@@ -417,13 +417,13 @@ func (by *Bybit) wsUSDTHandleData(respRaw []byte) error {
by.Websocket.DataHandler <- &ticker.Price{
ExchangeName: by.Name,
Last: response.Data.Insert[x].LastPrice,
High: response.Data.Insert[x].HighPrice24h,
Low: response.Data.Insert[x].LowPrice24h,
Last: response.Data.Insert[x].LastPrice.Float64(),
High: response.Data.Insert[x].HighPrice24h.Float64(),
Low: response.Data.Insert[x].LowPrice24h.Float64(),
Bid: response.Data.Insert[x].BidPrice,
Ask: response.Data.Insert[x].AskPrice,
Volume: response.Data.Insert[x].Volume24h,
Close: response.Data.Insert[x].PrevPrice24h,
Close: response.Data.Insert[x].PrevPrice24h.Float64(),
LastUpdated: response.Data.Insert[x].UpdateAt,
AssetType: asset.USDTMarginedFutures,
Pair: p,
@@ -493,11 +493,11 @@ func (by *Bybit) wsUSDTHandleData(respRaw []byte) error {
Pair: p,
Side: oSide,
Status: oStatus,
Price: response.Data[i].Price,
Price: response.Data[i].Price.Float64(),
Amount: response.Data[i].OrderQty,
Trades: []order.TradeHistory{
{
Price: response.Data[i].Price,
Price: response.Data[i].Price.Float64(),
Amount: response.Data[i].OrderQty,
Exchange: by.Name,
Side: oSide,
@@ -547,7 +547,7 @@ func (by *Bybit) wsUSDTHandleData(respRaw []byte) error {
}
}
by.Websocket.DataHandler <- &order.Detail{
Price: response.Data[x].Price,
Price: response.Data[x].Price.Float64(),
Amount: response.Data[x].OrderQty,
Exchange: by.Name,
OrderID: response.Data[x].OrderID,
@@ -559,7 +559,7 @@ func (by *Bybit) wsUSDTHandleData(respRaw []byte) error {
Pair: p,
Trades: []order.TradeHistory{
{
Price: response.Data[x].Price,
Price: response.Data[x].Price.Float64(),
Amount: response.Data[x].OrderQty,
Exchange: by.Name,
Side: oSide,
@@ -609,7 +609,7 @@ func (by *Bybit) wsUSDTHandleData(respRaw []byte) error {
}
}
by.Websocket.DataHandler <- &order.Detail{
Price: response.Data[x].Price,
Price: response.Data[x].Price.Float64(),
Amount: response.Data[x].OrderQty,
Exchange: by.Name,
OrderID: response.Data[x].OrderID,
@@ -622,7 +622,7 @@ func (by *Bybit) wsUSDTHandleData(respRaw []byte) error {
Pair: p,
Trades: []order.TradeHistory{
{
Price: response.Data[x].Price,
Price: response.Data[x].Price.Float64(),
Amount: response.Data[x].OrderQty,
Exchange: by.Name,
Side: oSide,

View File

@@ -1,6 +1,10 @@
package bybit
import "time"
import (
"time"
"github.com/thrasher-corp/gocryptotrader/common/convert"
)
var (
validFuturesIntervals = []string{
@@ -15,10 +19,10 @@ var (
// OrderbookData stores ob data for cmargined futures
type OrderbookData struct {
Symbol string `json:"symbol"`
Price float64 `json:"price,string"`
Size float64 `json:"size"`
Side string `json:"side"`
Symbol string `json:"symbol"`
Price convert.StringToFloat64 `json:"price"`
Size float64 `json:"size"`
Side string `json:"side"`
}
// FuturesCandleStick holds kline data
@@ -37,46 +41,46 @@ type FuturesCandleStick struct {
// FuturesCandleStickWithStringParam holds kline data
type FuturesCandleStickWithStringParam struct {
ID int64 `json:"id"`
Symbol string `json:"symbol"`
Interval string `json:"interval"`
OpenTime int64 `json:"open_time"`
Open float64 `json:"open,string"`
High float64 `json:"high,string"`
Low float64 `json:"low,string"`
Close float64 `json:"close,string"`
Volume float64 `json:"volume,string"`
TurnOver float64 `json:"turnover,string"`
ID int64 `json:"id"`
Symbol string `json:"symbol"`
Interval string `json:"interval"`
OpenTime int64 `json:"open_time"`
Open convert.StringToFloat64 `json:"open"`
High convert.StringToFloat64 `json:"high"`
Low convert.StringToFloat64 `json:"low"`
Close convert.StringToFloat64 `json:"close"`
Volume convert.StringToFloat64 `json:"volume"`
TurnOver convert.StringToFloat64 `json:"turnover"`
}
// SymbolPriceTicker stores ticker price stats
type SymbolPriceTicker struct {
Symbol string `json:"symbol"`
BidPrice float64 `json:"bid_price,string"`
AskPrice float64 `json:"ask_price,string"`
LastPrice float64 `json:"last_price,string"`
LastTickDirection string `json:"last_tick_direction"`
Price24hAgo float64 `json:"prev_price_24h,string"`
PricePcntChange24h float64 `json:"price_24h_pcnt,string"`
HighPrice24h float64 `json:"high_price_24h,string"`
LowPrice24h float64 `json:"low_price_24h,string"`
Price1hAgo float64 `json:"prev_price_1h,string"`
PricePcntChange1h bybitNumericalValue `json:"price_1h_pcnt"`
MarkPrice float64 `json:"mark_price,string"`
IndexPrice float64 `json:"index_price,string"`
OpenInterest float64 `json:"open_interest"`
OpenValue bybitNumericalValue `json:"open_value"`
TotalTurnover bybitNumericalValue `json:"total_turnover"`
Turnover24h float64 `json:"turnover_24h,string"`
TotalVolume float64 `json:"total_volume"`
Volume24h float64 `json:"volume_24h"`
FundingRate float64 `json:"funding_rate,string"`
PredictedFundingRate bybitNumericalValue `json:"predicted_funding_rate"`
NextFundingTime string `json:"next_funding_time"`
CountdownHour int64 `json:"countdown_hour"`
DeliveryFeeRate bybitNumericalValue `json:"delivery_fee_rate"`
PredictedDeliveryPrice bybitNumericalValue `json:"predicted_delivery_price"`
DeliveryTime string `json:"delivery_time"`
Symbol string `json:"symbol"`
BidPrice convert.StringToFloat64 `json:"bid_price"`
AskPrice convert.StringToFloat64 `json:"ask_price"`
LastPrice convert.StringToFloat64 `json:"last_price"`
LastTickDirection string `json:"last_tick_direction"`
Price24hAgo convert.StringToFloat64 `json:"prev_price_24h"`
PricePcntChange24h convert.StringToFloat64 `json:"price_24h_pcnt"`
HighPrice24h convert.StringToFloat64 `json:"high_price_24h"`
LowPrice24h convert.StringToFloat64 `json:"low_price_24h"`
Price1hAgo convert.StringToFloat64 `json:"prev_price_1h"`
PricePcntChange1h convert.StringToFloat64 `json:"price_1h_pcnt"`
MarkPrice convert.StringToFloat64 `json:"mark_price"`
IndexPrice convert.StringToFloat64 `json:"index_price"`
OpenInterest float64 `json:"open_interest"`
OpenValue convert.StringToFloat64 `json:"open_value"`
TotalTurnover convert.StringToFloat64 `json:"total_turnover"`
Turnover24h convert.StringToFloat64 `json:"turnover_24h"`
TotalVolume float64 `json:"total_volume"`
Volume24h float64 `json:"volume_24h"`
FundingRate convert.StringToFloat64 `json:"funding_rate"`
PredictedFundingRate convert.StringToFloat64 `json:"predicted_funding_rate"`
NextFundingTime string `json:"next_funding_time"`
CountdownHour int64 `json:"countdown_hour"`
DeliveryFeeRate convert.StringToFloat64 `json:"delivery_fee_rate"`
PredictedDeliveryPrice convert.StringToFloat64 `json:"predicted_delivery_price"`
DeliveryTime string `json:"delivery_time"`
}
// FuturesPublicTradesData stores recent public trades for futures
@@ -101,14 +105,14 @@ type SymbolInfo struct {
MakerFee string `json:"maker_fee"`
FundingFeeInterval int64 `json:"funding_interval"`
LeverageFilter struct {
MinLeverage float64 `json:"min_leverage"`
MaxLeverage float64 `json:"max_leverage"`
LeverageStep float64 `json:"leverage_step,string"`
MinLeverage float64 `json:"min_leverage"`
MaxLeverage float64 `json:"max_leverage"`
LeverageStep convert.StringToFloat64 `json:"leverage_step"`
} `json:"leverage_filter"`
PriceFilter struct {
MinPrice float64 `json:"min_price,string"`
MaxPrice float64 `json:"max_price,string"`
TickSize float64 `json:"tick_size,string"`
MinPrice convert.StringToFloat64 `json:"min_price"`
MaxPrice convert.StringToFloat64 `json:"max_price"`
TickSize convert.StringToFloat64 `json:"tick_size"`
} `json:"price_filter"`
LotSizeFilter struct {
MinTradeQty float64 `json:"min_trading_qty"`
@@ -131,13 +135,13 @@ type MarkPriceKlineData struct {
// IndexPriceKlineData stores index price kline data
type IndexPriceKlineData struct {
Symbol string `json:"symbol"`
Interval string `json:"period"`
StartAt int64 `json:"open_time"`
Open float64 `json:"open,string"`
High float64 `json:"high,string"`
Low float64 `json:"low,string"`
Close float64 `json:"close,string"`
Symbol string `json:"symbol"`
Interval string `json:"period"`
StartAt int64 `json:"open_time"`
Open convert.StringToFloat64 `json:"open"`
High convert.StringToFloat64 `json:"high"`
Low convert.StringToFloat64 `json:"low"`
Close convert.StringToFloat64 `json:"close"`
}
// OpenInterestData stores open interest data
@@ -242,35 +246,35 @@ type FuturesRealtimeOrderData struct {
// FuturesActiveRealtimeOrder stores future active realtime order
type FuturesActiveRealtimeOrder struct {
FuturesRealtimeOrderData
ExtensionField map[string]interface{} `json:"ext_fields"`
LastExecutionTime string `json:"last_exec_time"`
LastExecutionPrice float64 `json:"last_exec_price"`
LeavesQty float64 `json:"leaves_qty"`
LeaveValue float64 `json:"leaves_value,string"`
CumulativeQty float64 `json:"cum_exec_qty,string"`
CumulativeValue float64 `json:"cum_exec_value,string"`
CumulativeFee float64 `json:"cum_exec_fee,string"`
RejectReason string `json:"reject_reason"`
CancelType string `json:"cancel_type"`
CreatedAt time.Time `json:"create_at"`
UpdatedAt time.Time `json:"updated_at"`
OrderID string `json:"order_id"`
ExtensionField map[string]interface{} `json:"ext_fields"`
LastExecutionTime string `json:"last_exec_time"`
LastExecutionPrice float64 `json:"last_exec_price"`
LeavesQty float64 `json:"leaves_qty"`
LeaveValue convert.StringToFloat64 `json:"leaves_value"`
CumulativeQty convert.StringToFloat64 `json:"cum_exec_qty"`
CumulativeValue convert.StringToFloat64 `json:"cum_exec_value"`
CumulativeFee convert.StringToFloat64 `json:"cum_exec_fee"`
RejectReason string `json:"reject_reason"`
CancelType string `json:"cancel_type"`
CreatedAt time.Time `json:"create_at"`
UpdatedAt time.Time `json:"updated_at"`
OrderID string `json:"order_id"`
}
// CoinFuturesConditionalRealtimeOrder stores CMF future coinditional realtime order
type CoinFuturesConditionalRealtimeOrder struct {
FuturesRealtimeOrderData
ExtensionField map[string]interface{} `json:"ext_fields"`
LeavesQty float64 `json:"leaves_qty"`
LeaveValue float64 `json:"leaves_value,string"`
CumulativeQty float64 `json:"cum_exec_qty,string"`
CumulativeValue float64 `json:"cum_exec_value,string"`
CumulativeFee float64 `json:"cum_exec_fee,string"`
RejectReason string `json:"reject_reason"`
CancelType string `json:"cancel_type"`
CreatedAt string `json:"create_at"`
UpdatedAt string `json:"updated_at"`
OrderID string `json:"order_id"`
ExtensionField map[string]interface{} `json:"ext_fields"`
LeavesQty float64 `json:"leaves_qty"`
LeaveValue convert.StringToFloat64 `json:"leaves_value"`
CumulativeQty convert.StringToFloat64 `json:"cum_exec_qty"`
CumulativeValue convert.StringToFloat64 `json:"cum_exec_value"`
CumulativeFee convert.StringToFloat64 `json:"cum_exec_fee"`
RejectReason string `json:"reject_reason"`
CancelType string `json:"cancel_type"`
CreatedAt string `json:"create_at"`
UpdatedAt string `json:"updated_at"`
OrderID string `json:"order_id"`
}
// FuturesConditionalRealtimeOrder stores future conditional realtime order
@@ -375,10 +379,10 @@ type FuturesCancelOrderData struct {
// FuturesCancelOrderResp stores future cancel order response
type FuturesCancelOrderResp struct {
FuturesCancelOrderData
StopOrderType string `json:"stop_order_type"`
TriggerBy string `json:"trigger_by"`
BasePrice float64 `json:"base_price,string"`
ExpectedDirection string `json:"expected_direction"`
StopOrderType string `json:"stop_order_type"`
TriggerBy string `json:"trigger_by"`
BasePrice convert.StringToFloat64 `json:"base_price"`
ExpectedDirection string `json:"expected_direction"`
}
// RiskInfo stores risk information
@@ -397,23 +401,23 @@ type RiskInfo struct {
// RiskInfoWithStringParam stores risk information where string params
type RiskInfoWithStringParam struct {
ID int64 `json:"id"`
Symbol string `json:"symbol"`
Limit int64 `json:"limit"`
MaintainMargin float64 `json:"maintain_margin,string"`
StartingMargin float64 `json:"starting_margin,string"`
Section []string `json:"section"`
IsLowestRisk int64 `json:"is_lowest_risk"`
CreatedAt string `json:"create_at"`
UpdateAt string `json:"updated_at"`
MaxLeverage float64 `json:"max_leverage,string"`
ID int64 `json:"id"`
Symbol string `json:"symbol"`
Limit int64 `json:"limit"`
MaintainMargin convert.StringToFloat64 `json:"maintain_margin"`
StartingMargin convert.StringToFloat64 `json:"starting_margin"`
Section []string `json:"section"`
IsLowestRisk int64 `json:"is_lowest_risk"`
CreatedAt string `json:"create_at"`
UpdateAt string `json:"updated_at"`
MaxLeverage convert.StringToFloat64 `json:"max_leverage"`
}
// FundingInfo stores funding information
type FundingInfo struct {
Symbol string `json:"symbol"`
FundingRate float64 `json:"funding_rate,string"`
FundingRateTimestamp int64 `json:"funding_rate_timestamp"`
Symbol string `json:"symbol"`
FundingRate convert.StringToFloat64 `json:"funding_rate"`
FundingRateTimestamp int64 `json:"funding_rate_timestamp"`
}
// USDTFundingInfo stores USDT funding information
@@ -451,19 +455,19 @@ type Position struct {
// PositionWithStringParam stores position with string params
type PositionWithStringParam struct {
UserID int64 `json:"user_id"`
Symbol string `json:"symbol"`
Side string `json:"side"`
Size float64 `json:"size"`
PositionValue float64 `json:"position_value,string"`
EntryPrice float64 `json:"entry_price,string"`
LiquidationPrice float64 `json:"liq_price,string"`
BankruptcyPrice float64 `json:"bust_price,string"`
Leverage float64 `json:"leverage,string"`
PositionMargin float64 `json:"position_margin,string"`
OccupiedClosingFee float64 `json:"occ_closing_fee,string"`
RealisedPNL float64 `json:"realised_pnl,string"`
AccumulatedRealisedPNL float64 `json:"cum_realised_pnl,string"`
UserID int64 `json:"user_id"`
Symbol string `json:"symbol"`
Side string `json:"side"`
Size float64 `json:"size"`
PositionValue convert.StringToFloat64 `json:"position_value"`
EntryPrice convert.StringToFloat64 `json:"entry_price"`
LiquidationPrice convert.StringToFloat64 `json:"liq_price"`
BankruptcyPrice convert.StringToFloat64 `json:"bust_price"`
Leverage convert.StringToFloat64 `json:"leverage"`
PositionMargin convert.StringToFloat64 `json:"position_margin"`
OccupiedClosingFee convert.StringToFloat64 `json:"occ_closing_fee"`
RealisedPNL convert.StringToFloat64 `json:"realised_pnl"`
AccumulatedRealisedPNL convert.StringToFloat64 `json:"cum_realised_pnl"`
}
// PositionData stores position data
@@ -482,54 +486,54 @@ type PositionData struct {
// PositionDataWithStringParam stores position data with string params
type PositionDataWithStringParam struct {
PositionWithStringParam
IsIsolated bool `json:"is_isolated"`
AutoAddMargin int64 `json:"auto_add_margin"`
UnrealisedPNL float64 `json:"unrealised_pnl"`
DeleverageIndicator int64 `json:"deleverage_indicator"`
RiskID int64 `json:"risk_id"`
TakeProfit float64 `json:"take_profit,string"`
StopLoss float64 `json:"stop_loss,string"`
TrailingStop float64 `json:"trailing_stop,string"`
IsIsolated bool `json:"is_isolated"`
AutoAddMargin int64 `json:"auto_add_margin"`
UnrealisedPNL float64 `json:"unrealised_pnl"`
DeleverageIndicator int64 `json:"deleverage_indicator"`
RiskID int64 `json:"risk_id"`
TakeProfit convert.StringToFloat64 `json:"take_profit"`
StopLoss convert.StringToFloat64 `json:"stop_loss"`
TrailingStop convert.StringToFloat64 `json:"trailing_stop"`
}
// PositionResp stores position response
type PositionResp struct {
PositionDataWithStringParam
PositionID int64 `json:"position_idx"`
Mode int64 `json:"mode"`
ID int64 `json:"id"`
EffectiveLeverage float64 `json:"effective_leverage,string"`
OccupiedFundingFee float64 `json:"occ_funding_fee,string"`
PositionStatus string `json:"position_status"`
CalculatedData string `json:"oc_calc_data"`
OrderMargin float64 `json:"order_margin,string"`
WalletBalance float64 `json:"wallet_balance,string"`
CrossSequence int64 `json:"cross_seq"`
PositionSequence int64 `json:"position_seq"`
TakeProfitStopLossMode string `json:"tp_sl_mode"`
CreatedAt string `json:"created_at"`
UpdateAt string `json:"updated_at"`
PositionID int64 `json:"position_idx"`
Mode int64 `json:"mode"`
ID int64 `json:"id"`
EffectiveLeverage convert.StringToFloat64 `json:"effective_leverage"`
OccupiedFundingFee convert.StringToFloat64 `json:"occ_funding_fee"`
PositionStatus string `json:"position_status"`
CalculatedData string `json:"oc_calc_data"`
OrderMargin convert.StringToFloat64 `json:"order_margin"`
WalletBalance convert.StringToFloat64 `json:"wallet_balance"`
CrossSequence int64 `json:"cross_seq"`
PositionSequence int64 `json:"position_seq"`
TakeProfitStopLossMode string `json:"tp_sl_mode"`
CreatedAt string `json:"created_at"`
UpdateAt string `json:"updated_at"`
}
// SetTradingAndStopResp stores set trading and stop response
type SetTradingAndStopResp struct {
PositionData
ID int64 `json:"id"`
RiskID int64 `json:"risk_id"`
AutoAddMargin int64 `json:"auto_add_margin"`
OccupiedFundingFee float64 `json:"occ_funding_fee,string"`
TakeProfit float64 `json:"take_profit,string"`
StopLoss float64 `json:"stop_loss,string"`
PositionStatus string `json:"position_status"`
DeleverageIndicator int64 `json:"deleverage_indicator"`
CalculatedData string `json:"oc_calc_data"`
OrderMargin float64 `json:"order_margin,string"`
WalletBalance float64 `json:"wallet_balance,string"`
CrossSequence int64 `json:"cross_seq"`
PositionSequence int64 `json:"position_seq"`
CreatedAt string `json:"created_at"`
UpdateAt string `json:"updated_at"`
ExtensionField map[string]interface{} `json:"ext_fields"`
ID int64 `json:"id"`
RiskID int64 `json:"risk_id"`
AutoAddMargin int64 `json:"auto_add_margin"`
OccupiedFundingFee convert.StringToFloat64 `json:"occ_funding_fee"`
TakeProfit convert.StringToFloat64 `json:"take_profit"`
StopLoss convert.StringToFloat64 `json:"stop_loss"`
PositionStatus string `json:"position_status"`
DeleverageIndicator int64 `json:"deleverage_indicator"`
CalculatedData string `json:"oc_calc_data"`
OrderMargin convert.StringToFloat64 `json:"order_margin"`
WalletBalance convert.StringToFloat64 `json:"wallet_balance"`
CrossSequence int64 `json:"cross_seq"`
PositionSequence int64 `json:"position_seq"`
CreatedAt string `json:"created_at"`
UpdateAt string `json:"updated_at"`
ExtensionField map[string]interface{} `json:"ext_fields"`
}
// USDTPositionResp stores USDT position response
@@ -547,24 +551,24 @@ type UpdateMarginResp struct {
// TradeData stores trade data
type TradeData struct {
OrderID string `json:"order_id"`
OrderLinkedID string `json:"order_link_id"`
OrderSide string `json:"side"`
Symbol string `json:"symbol"`
ExecutionID string `json:"exec_id"`
OrderPrice float64 `json:"order_price"`
OrderQty float64 `json:"order_qty"`
OrderType string `json:"order_type"`
FeeRate float64 `json:"fee_rate"`
ExecutionFee float64 `json:"exec_fee,string"`
ExecutionPrice float64 `json:"exec_price,string"`
ExecutionQty float64 `json:"exec_qty"`
ExecutionType string `json:"exec_type"`
ExecutionValue float64 `json:"exec_value,string"`
LeavesQty float64 `json:"leaves_qty"`
ClosedSize float64 `json:"closed_size"`
LastLiquidity string `json:"last_liquidity_ind"`
TradeTimeMs int64 `json:"trade_time_ms"`
OrderID string `json:"order_id"`
OrderLinkedID string `json:"order_link_id"`
OrderSide string `json:"side"`
Symbol string `json:"symbol"`
ExecutionID string `json:"exec_id"`
OrderPrice float64 `json:"order_price"`
OrderQty float64 `json:"order_qty"`
OrderType string `json:"order_type"`
FeeRate float64 `json:"fee_rate"`
ExecutionFee convert.StringToFloat64 `json:"exec_fee"`
ExecutionPrice convert.StringToFloat64 `json:"exec_price"`
ExecutionQty float64 `json:"exec_qty"`
ExecutionType string `json:"exec_type"`
ExecutionValue convert.StringToFloat64 `json:"exec_value"`
LeavesQty float64 `json:"leaves_qty"`
ClosedSize float64 `json:"closed_size"`
LastLiquidity string `json:"last_liquidity_ind"`
TradeTimeMs int64 `json:"trade_time_ms"`
}
// TradeResp stores trade response
@@ -650,30 +654,30 @@ type WalletData struct {
// FundRecord stores funding records
type FundRecord struct {
ID int64 `json:"id"`
UserID int64 `json:"user_id"`
Coin string `json:"coin"`
Type string `json:"type"`
Amount float64 `json:"amount,string"`
TxID string `json:"tx_id"`
Address string `json:"address"`
WalletBalance float64 `json:"wallet_balance,string"`
ExecutionTime string `json:"exec_time"`
CrossSequence int64 `json:"cross_seq"`
ID int64 `json:"id"`
UserID int64 `json:"user_id"`
Coin string `json:"coin"`
Type string `json:"type"`
Amount convert.StringToFloat64 `json:"amount"`
TxID string `json:"tx_id"`
Address string `json:"address"`
WalletBalance convert.StringToFloat64 `json:"wallet_balance"`
ExecutionTime string `json:"exec_time"`
CrossSequence int64 `json:"cross_seq"`
}
// FundWithdrawalRecord stores funding withdrawal records
type FundWithdrawalRecord struct {
ID int64 `json:"id"`
UserID int64 `json:"user_id"`
Coin string `json:"coin"`
Status string `json:"status"`
Amount float64 `json:"amount,string"`
Fee float64 `json:"fee"`
Address string `json:"address"`
TxID string `json:"tx_id"`
SubmittedAt time.Time `json:"submited_at"`
UpdatedAt time.Time `json:"updated_at"`
ID int64 `json:"id"`
UserID int64 `json:"user_id"`
Coin string `json:"coin"`
Status string `json:"status"`
Amount convert.StringToFloat64 `json:"amount"`
Fee float64 `json:"fee"`
Address string `json:"address"`
TxID string `json:"tx_id"`
SubmittedAt time.Time `json:"submited_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// AssetExchangeRecord stores asset exchange records
@@ -690,79 +694,79 @@ type AssetExchangeRecord struct {
// USDCOrderbookData stores orderbook data for USDCMarginedFutures
type USDCOrderbookData struct {
Price float64 `json:"price,string"`
Size float64 `json:"size,string"`
Side string `json:"side"`
Price convert.StringToFloat64 `json:"price"`
Size convert.StringToFloat64 `json:"size"`
Side string `json:"side"`
}
// USDCContract stores contract data
type USDCContract struct {
Symbol string `json:"symbol"`
Status string `json:"status"`
BaseCoin string `json:"baseCoin"`
QuoteCoin string `json:"quoteCoin"`
TakerFeeRate float64 `json:"takerFeeRate,string"`
MakerFeeRate float64 `json:"makerFeeRate,string"`
MinLeverage float64 `json:"minLeverage,string"`
MaxLeverage float64 `json:"maxLeverage,string"`
LeverageStep float64 `json:"leverageStep,string"`
MinPrice float64 `json:"minPrice,string"`
MaxPrice float64 `json:"maxPrice,string"`
TickSize float64 `json:"tickSize,string"`
MaxTradingQty float64 `json:"maxTradingQty,string"`
MinTradingQty float64 `json:"minTradingQty,string"`
QtyStep float64 `json:"qtyStep,string"`
DeliveryTime bybitTimeMilliSecStr `json:"deliveryTime"`
Symbol string `json:"symbol"`
Status string `json:"status"`
BaseCoin string `json:"baseCoin"`
QuoteCoin string `json:"quoteCoin"`
TakerFeeRate convert.StringToFloat64 `json:"takerFeeRate"`
MakerFeeRate convert.StringToFloat64 `json:"makerFeeRate"`
MinLeverage convert.StringToFloat64 `json:"minLeverage"`
MaxLeverage convert.StringToFloat64 `json:"maxLeverage"`
LeverageStep convert.StringToFloat64 `json:"leverageStep"`
MinPrice convert.StringToFloat64 `json:"minPrice"`
MaxPrice convert.StringToFloat64 `json:"maxPrice"`
TickSize convert.StringToFloat64 `json:"tickSize"`
MaxTradingQty convert.StringToFloat64 `json:"maxTradingQty"`
MinTradingQty convert.StringToFloat64 `json:"minTradingQty"`
QtyStep convert.StringToFloat64 `json:"qtyStep"`
DeliveryTime bybitTimeMilliSecStr `json:"deliveryTime"`
}
// USDCSymbol stores symbol data
type USDCSymbol struct {
Symbol string `json:"symbol"`
NextFundingTime string `json:"nextFundingTime"`
Bid float64 `json:"bid,string"`
BidSize float64 `json:"bidSize,string"`
Ask float64 `json:"ask,string"`
AskSize float64 `json:"askSize,string"`
LastPrice float64 `json:"lastPrice,string"`
OpenInterest float64 `json:"openInterest,string"`
IndexPrice float64 `json:"indexPrice,string"`
MarkPrice float64 `json:"markPrice,string"`
Change24h float64 `json:"change24h,string"`
High24h float64 `json:"high24h,string"`
Low24h float64 `json:"low24h,string"`
Volume24h float64 `json:"volume24h,string"`
Turnover24h float64 `json:"turnover24h,string"`
TotalVolume float64 `json:"totalVolume,string"`
TotalTurnover float64 `json:"totalTurnover,string"`
FundingRate float64 `json:"fundingRate,string"`
PredictedFundingRate float64 `json:"predictedFundingRate,string"`
CountdownHour float64 `json:"countdownHour,string"`
UnderlyingPrice string `json:"underlyingPrice"`
Symbol string `json:"symbol"`
NextFundingTime string `json:"nextFundingTime"`
Bid convert.StringToFloat64 `json:"bid"`
BidSize convert.StringToFloat64 `json:"bidSize"`
Ask convert.StringToFloat64 `json:"ask"`
AskSize convert.StringToFloat64 `json:"askSize"`
LastPrice convert.StringToFloat64 `json:"lastPrice"`
OpenInterest convert.StringToFloat64 `json:"openInterest"`
IndexPrice convert.StringToFloat64 `json:"indexPrice"`
MarkPrice convert.StringToFloat64 `json:"markPrice"`
Change24h convert.StringToFloat64 `json:"change24h"`
High24h convert.StringToFloat64 `json:"high24h"`
Low24h convert.StringToFloat64 `json:"low24h"`
Volume24h convert.StringToFloat64 `json:"volume24h"`
Turnover24h convert.StringToFloat64 `json:"turnover24h"`
TotalVolume convert.StringToFloat64 `json:"totalVolume"`
TotalTurnover convert.StringToFloat64 `json:"totalTurnover"`
FundingRate convert.StringToFloat64 `json:"fundingRate"`
PredictedFundingRate convert.StringToFloat64 `json:"predictedFundingRate"`
CountdownHour convert.StringToFloat64 `json:"countdownHour"`
UnderlyingPrice string `json:"underlyingPrice"`
}
// USDCKlineBase stores Kline Base
type USDCKlineBase struct {
Symbol string `json:"symbol"`
Period string `json:"period"`
OpenTime bybitTimeSecStr `json:"openTime"`
Open float64 `json:"open,string"`
High float64 `json:"high,string"`
Low float64 `json:"low,string"`
Close float64 `json:"close,string"`
Symbol string `json:"symbol"`
Period string `json:"period"`
OpenTime bybitTimeSecStr `json:"openTime"`
Open convert.StringToFloat64 `json:"open"`
High convert.StringToFloat64 `json:"high"`
Low convert.StringToFloat64 `json:"low"`
Close convert.StringToFloat64 `json:"close"`
}
// USDCKline stores kline data
type USDCKline struct {
USDCKlineBase
Volume float64 `json:"volume,string"`
Turnover float64 `json:"turnover,string"`
Volume convert.StringToFloat64 `json:"volume"`
Turnover convert.StringToFloat64 `json:"turnover"`
}
// USDCOpenInterest stores open interest data
type USDCOpenInterest struct {
Symbol string `json:"symbol"`
Timestamp bybitTimeMilliSecStr `json:"timestamp"`
OpenInterest float64 `json:"openInterest,string"`
Symbol string `json:"symbol"`
Timestamp bybitTimeMilliSecStr `json:"timestamp"`
OpenInterest convert.StringToFloat64 `json:"openInterest"`
}
// USDCLargeOrder stores large order data
@@ -783,184 +787,191 @@ type USDCAccountRatio struct {
// USDCTrade stores trade data
type USDCTrade struct {
ID string `json:"id"`
Symbol string `json:"symbol"`
OrderPrice float64 `json:"orderPrice,string"`
OrderQty float64 `json:"orderQty,string"`
Side string `json:"side"`
Timestamp bybitTimeMilliSecStr `json:"time"`
ID string `json:"id"`
Symbol string `json:"symbol"`
OrderPrice convert.StringToFloat64 `json:"orderPrice"`
OrderQty convert.StringToFloat64 `json:"orderQty"`
Side string `json:"side"`
Timestamp bybitTimeMilliSecStr `json:"time"`
}
// USDCCreateOrderResp stores create order response
type USDCCreateOrderResp struct {
ID string `json:"orderId"`
OrderLinkID string `json:"orderLinkId"`
Symbol string `json:"symbol"`
OrderPrice float64 `json:"orderPrice,string"`
OrderQty float64 `json:"orderQty,string"`
OrderType string `json:"orderType"`
Side string `json:"side"`
ID string `json:"orderId"`
OrderLinkID string `json:"orderLinkId"`
Symbol string `json:"symbol"`
OrderPrice convert.StringToFloat64 `json:"orderPrice"`
OrderQty convert.StringToFloat64 `json:"orderQty"`
OrderType string `json:"orderType"`
Side string `json:"side"`
}
// USDCOrder store order data
type USDCOrder struct {
ID string `json:"orderId"`
OrderLinkID string `json:"orderLinkId"`
Symbol string `json:"symbol"`
OrderType string `json:"orderType"`
Side string `json:"side"`
Qty float64 `json:"qty,string"`
Price float64 `json:"price,string"`
TimeInForce string `json:"timeInForce"`
TotalOrderValue float64 `json:"cumExecValue,string"`
TotalFilledQty float64 `json:"cumExecQty,string"`
TotalFee float64 `json:"cumExecFee,string"`
InitialMargin string `json:"orderIM"`
OrderStatus string `json:"orderStatus"`
TakeProfit float64 `json:"takeProfit,string"`
StopLoss float64 `json:"stopLoss,string"`
TPTriggerBy string `json:"tpTriggerBy"`
SLTriggerBy string `json:"slTriggerBy"`
LastExecPrice float64 `json:"lastExecPrice"`
BasePrice string `json:"basePrice"`
TriggerPrice float64 `json:"triggerPrice,string"`
TriggerBy string `json:"triggerBy"`
ReduceOnly bool `json:"reduceOnly"`
StopOrderType string `json:"stopOrderType"`
CloseOnTrigger string `json:"closeOnTrigger"`
CreatedAt bybitTimeMilliSecStr `json:"createdAt"`
ID string `json:"orderId"`
OrderLinkID string `json:"orderLinkId"`
Symbol string `json:"symbol"`
OrderType string `json:"orderType"`
Side string `json:"side"`
Qty convert.StringToFloat64 `json:"qty"`
Price convert.StringToFloat64 `json:"price"`
TimeInForce string `json:"timeInForce"`
TotalOrderValue convert.StringToFloat64 `json:"cumExecValue"`
TotalFilledQty convert.StringToFloat64 `json:"cumExecQty"`
TotalFee convert.StringToFloat64 `json:"cumExecFee"`
InitialMargin string `json:"orderIM"`
OrderStatus string `json:"orderStatus"`
TakeProfit convert.StringToFloat64 `json:"takeProfit"`
StopLoss convert.StringToFloat64 `json:"stopLoss"`
TPTriggerBy string `json:"tpTriggerBy"`
SLTriggerBy string `json:"slTriggerBy"`
LastExecPrice float64 `json:"lastExecPrice"`
BasePrice string `json:"basePrice"`
TriggerPrice convert.StringToFloat64 `json:"triggerPrice"`
TriggerBy string `json:"triggerBy"`
ReduceOnly bool `json:"reduceOnly"`
StopOrderType string `json:"stopOrderType"`
CloseOnTrigger string `json:"closeOnTrigger"`
CreatedAt bybitTimeMilliSecStr `json:"createdAt"`
}
// USDCOrderHistory stores order history
type USDCOrderHistory struct {
USDCOrder
LeavesQty float64 `json:"leavesQty,string"` // Est. unfilled order qty
CashFlow string `json:"cashFlow"`
RealisedPnl float64 `json:"realisedPnl,string"`
UpdatedAt bybitTimeMilliSecStr `json:"updatedAt"`
LeavesQty convert.StringToFloat64 `json:"leavesQty"` // Est. unfilled order qty
CashFlow string `json:"cashFlow"`
RealisedPnl convert.StringToFloat64 `json:"realisedPnl"`
UpdatedAt bybitTimeMilliSecStr `json:"updatedAt"`
}
// USDCTradeHistory stores trade history
type USDCTradeHistory struct {
ID string `json:"orderId"`
OrderLinkID string `json:"orderLinkId"`
Symbol string `json:"symbol"`
Side string `json:"side"`
TradeID string `json:"tradeId"`
ExecPrice float64 `json:"execPrice,string"`
ExecQty float64 `json:"execQty,string"`
ExecFee float64 `json:"execFee,string"`
FeeRate float64 `json:"feeRate,string"`
ExecType string `json:"execType"`
ExecValue float64 `json:"execValue,string"`
TradeTime bybitTimeMilliSecStr `json:"tradeTime"`
LastLiquidityInd string `json:"lastLiquidityInd"`
ID string `json:"orderId"`
OrderLinkID string `json:"orderLinkId"`
Symbol string `json:"symbol"`
Side string `json:"side"`
TradeID string `json:"tradeId"`
ExecPrice convert.StringToFloat64 `json:"execPrice"`
ExecQty convert.StringToFloat64 `json:"execQty"`
ExecFee convert.StringToFloat64 `json:"execFee"`
FeeRate convert.StringToFloat64 `json:"feeRate"`
ExecType string `json:"execType"`
ExecValue convert.StringToFloat64 `json:"execValue"`
TradeTime bybitTimeMilliSecStr `json:"tradeTime"`
LastLiquidityInd string `json:"lastLiquidityInd"`
}
// USDCTxLog stores transaction log data
type USDCTxLog struct {
TxTime bybitTimeMilliSecStr `json:"transactionTime"`
Symbol string `json:"symbol"`
Type string `json:"type"`
Side string `json:"side"`
Quantity float64 `json:"qty,string"`
Size float64 `json:"size,string"`
TradePrice float64 `json:"tradePrice,string"`
Funding float64 `json:"funding,string"`
Fee float64 `json:"fee,string"`
CashFlow string `json:"cashFlow"`
Change float64 `json:"change,string"`
WalletBalance float64 `json:"walletBalance,string"`
FeeRate float64 `json:"feeRate,string"`
TradeID string `json:"tradeId"`
OrderID string `json:"orderId"`
OrderLinkID string `json:"orderLinkId"`
Info string `json:"info"`
TxTime bybitTimeMilliSecStr `json:"transactionTime"`
Symbol string `json:"symbol"`
Type string `json:"type"`
Side string `json:"side"`
Quantity convert.StringToFloat64 `json:"qty"`
Size convert.StringToFloat64 `json:"size"`
TradePrice convert.StringToFloat64 `json:"tradePrice"`
Funding convert.StringToFloat64 `json:"funding"`
Fee convert.StringToFloat64 `json:"fee"`
CashFlow string `json:"cashFlow"`
Change convert.StringToFloat64 `json:"change"`
WalletBalance convert.StringToFloat64 `json:"walletBalance"`
FeeRate convert.StringToFloat64 `json:"feeRate"`
TradeID string `json:"tradeId"`
OrderID string `json:"orderId"`
OrderLinkID string `json:"orderLinkId"`
Info string `json:"info"`
}
// USDCWalletBalance store USDC wallet balance
type USDCWalletBalance struct {
Equity float64 `json:"equity,string"`
WalletBalance float64 `json:"walletBalance,string"`
AvailableBalance float64 `json:"availableBalance,string"`
AccountIM float64 `json:"accountIM,string"`
AccountMM float64 `json:"accountMM,string"`
TotalRPL float64 `json:"totalRPL,string"`
TotalSessionUPL float64 `json:"totalSessionUPL,string"`
TotalSessionRPL float64 `json:"totalSessionRPL,string"`
Equity convert.StringToFloat64 `json:"equity"`
WalletBalance convert.StringToFloat64 `json:"walletBalance"`
AvailableBalance convert.StringToFloat64 `json:"availableBalance"`
AccountIM convert.StringToFloat64 `json:"accountIM"`
AccountMM convert.StringToFloat64 `json:"accountMM"`
TotalRPL convert.StringToFloat64 `json:"totalRPL"`
TotalSessionUPL convert.StringToFloat64 `json:"totalSessionUPL"`
TotalSessionRPL convert.StringToFloat64 `json:"totalSessionRPL"`
}
// USDCAssetInfo stores USDC asset data
type USDCAssetInfo struct {
BaseCoin string `json:"baseCoin"`
TotalDelta float64 `json:"totalDelta,string"`
TotalGamma float64 `json:"totalGamma,string"`
TotalVega float64 `json:"totalVega,string"`
TotalTheta float64 `json:"totalTheta,string"`
TotalRPL float64 `json:"totalRPL,string"`
SessionUPL float64 `json:"sessionUPL,string"`
SessionRPL float64 `json:"sessionRPL,string"`
IM float64 `json:"im,string"`
MM float64 `json:"mm,string"`
BaseCoin string `json:"baseCoin"`
TotalDelta convert.StringToFloat64 `json:"totalDelta"`
TotalGamma convert.StringToFloat64 `json:"totalGamma"`
TotalVega convert.StringToFloat64 `json:"totalVega"`
TotalTheta convert.StringToFloat64 `json:"totalTheta"`
TotalRPL convert.StringToFloat64 `json:"totalRPL"`
SessionUPL convert.StringToFloat64 `json:"sessionUPL"`
SessionRPL convert.StringToFloat64 `json:"sessionRPL"`
IM convert.StringToFloat64 `json:"im"`
MM convert.StringToFloat64 `json:"mm"`
}
// USDCPosition store USDC position data
type USDCPosition struct {
Symbol string `json:"symbol"`
Leverage float64 `json:"leverage,string"`
ClosingFee float64 `json:"occClosingFee,string"`
LiquidPrice string `json:"liqPrice"`
Position float64 `json:"positionValue"`
TakeProfit float64 `json:"takeProfit,string"`
RiskID string `json:"riskId"`
TrailingStop float64 `json:"trailingStop,string"`
UnrealisedPnl float64 `json:"unrealisedPnl,string"`
MarkPrice float64 `json:"markPrice,string"`
CumRealisedPnl float64 `json:"cumRealisedPnl,string"`
PositionMM float64 `json:"positionMM,string"`
PositionIM float64 `json:"positionIM,string"`
EntryPrice float64 `json:"entryPrice,string"`
Size float64 `json:"size,string"`
SessionRPL float64 `json:"sessionRPL,string"`
SessionUPL float64 `json:"sessionUPL,string"`
StopLoss float64 `json:"stopLoss,string"`
OrderMargin float64 `json:"orderMargin,string"`
SessionAvgPrice float64 `json:"sessionAvgPrice,string"`
CreatedAt bybitTimeMilliSecStr `json:"createdAt"`
UpdatedAt bybitTimeMilliSecStr `json:"updatedAt"`
TpSLMode string `json:"tpSLMode"`
Side string `json:"side"`
BustPrice string `json:"bustPrice"`
PositionStatus string `json:"positionStatus"`
DeleverageIndicator int64 `json:"deleverageIndicator"`
Symbol string `json:"symbol"`
Leverage convert.StringToFloat64 `json:"leverage"`
ClosingFee convert.StringToFloat64 `json:"occClosingFee"`
LiquidPrice string `json:"liqPrice"`
Position float64 `json:"positionValue"`
TakeProfit convert.StringToFloat64 `json:"takeProfit"`
RiskID string `json:"riskId"`
TrailingStop convert.StringToFloat64 `json:"trailingStop"`
UnrealisedPnl convert.StringToFloat64 `json:"unrealisedPnl"`
MarkPrice convert.StringToFloat64 `json:"markPrice"`
CumRealisedPnl convert.StringToFloat64 `json:"cumRealisedPnl"`
PositionMM convert.StringToFloat64 `json:"positionMM"`
PositionIM convert.StringToFloat64 `json:"positionIM"`
EntryPrice convert.StringToFloat64 `json:"entryPrice"`
Size convert.StringToFloat64 `json:"size"`
SessionRPL convert.StringToFloat64 `json:"sessionRPL"`
SessionUPL convert.StringToFloat64 `json:"sessionUPL"`
StopLoss convert.StringToFloat64 `json:"stopLoss"`
OrderMargin convert.StringToFloat64 `json:"orderMargin"`
SessionAvgPrice convert.StringToFloat64 `json:"sessionAvgPrice"`
CreatedAt bybitTimeMilliSecStr `json:"createdAt"`
UpdatedAt bybitTimeMilliSecStr `json:"updatedAt"`
TpSLMode string `json:"tpSLMode"`
Side string `json:"side"`
BustPrice string `json:"bustPrice"`
PositionStatus string `json:"positionStatus"`
DeleverageIndicator int64 `json:"deleverageIndicator"`
}
// USDCSettlementHistory store USDC settlement history data
type USDCSettlementHistory struct {
Symbol string `json:"symbol"`
Side string `json:"side"`
Time bybitTimeMilliSecStr `json:"time"`
Size float64 `json:"size,string"`
SessionAvgPrice float64 `json:"sessionAvgPrice,string"`
MarkPrice float64 `json:"markPrice,string"`
SessionRpl float64 `json:"sessionRpl,string"`
Symbol string `json:"symbol"`
Side string `json:"side"`
Time bybitTimeMilliSecStr `json:"time"`
Size convert.StringToFloat64 `json:"size"`
SessionAvgPrice convert.StringToFloat64 `json:"sessionAvgPrice"`
MarkPrice convert.StringToFloat64 `json:"markPrice"`
SessionRpl convert.StringToFloat64 `json:"sessionRpl"`
}
// USDCRiskLimit store USDC risk limit data
type USDCRiskLimit struct {
RiskID string `json:"riskId"`
Symbol string `json:"symbol"`
Limit string `json:"limit"`
Section []string `json:"section"`
StartingMargin float64 `json:"startingMargin,string"`
MaintainMargin float64 `json:"maintainMargin,string"`
IsLowestRisk bool `json:"isLowestRisk"`
MaxLeverage float64 `json:"maxLeverage,string"`
RiskID string `json:"riskId"`
Symbol string `json:"symbol"`
Limit string `json:"limit"`
Section []string `json:"section"`
StartingMargin convert.StringToFloat64 `json:"startingMargin"`
MaintainMargin convert.StringToFloat64 `json:"maintainMargin"`
IsLowestRisk bool `json:"isLowestRisk"`
MaxLeverage convert.StringToFloat64 `json:"maxLeverage"`
}
// USDCFundingInfo store USDC funding data
type USDCFundingInfo struct {
Symbol string `json:"symbol"`
Time bybitTimeMilliSecStr `json:"fundingRateTimestamp"`
Rate float64 `json:"fundingRate,string"`
Symbol string `json:"symbol"`
Time bybitTimeMilliSecStr `json:"fundingRateTimestamp"`
Rate convert.StringToFloat64 `json:"fundingRate"`
}
// CFuturesTradingFeeRate stores trading fee rate
type CFuturesTradingFeeRate struct {
TakerFeeRate convert.StringToFloat64 `json:"taker_fee_rate"`
MakerFeeRate convert.StringToFloat64 `json:"maker_fee_rate"`
UserID int64 `json:"user_id"`
}

View File

@@ -10,22 +10,26 @@ import (
)
const (
spotInterval = time.Second
spotRequestRate = 70
// See: https://bybit-exchange.github.io/docs/v5/rate-limit
spotInterval = time.Second * 5
spotRequestRate = 120
futuresPublicInterval = time.Second
futuresRequestRate = 50
spotPrivateRequestRate = 20
futuresInterval = time.Minute
futuresDefaultRateCount = 100
futuresOrderRate = 100
futuresOrderListRate = 600
futuresExecutionRate = 120
futuresPositionRateCount = 75
futuresPositionListRate = 120
futuresFundingRate = 120
futuresWalletRate = 120
futuresAccountRate = 600
spotPrivateInterval = time.Second
spotPrivateRequestRate = 20
spotPrivateFeeRequestRate = 10
futuresInterval = time.Minute
futuresDefaultRateCount = 100
futuresOrderRate = 100
futuresOrderListRate = 600
futuresExecutionRate = 120
futuresPositionRateCount = 75
futuresPositionListRate = 120
futuresFundingRate = 120
futuresWalletRate = 120
futuresAccountRate = 600
usdcPerpetualPublicRate = 50
usdcPerpetualCancelAllRate = 1
@@ -37,7 +41,7 @@ const (
publicSpotRate request.EndpointLimit = iota
publicFuturesRate
privateSpotRate
privateFeeRate
cFuturesDefaultRate
cFuturesCancelActiveOrderRate
@@ -153,6 +157,7 @@ type RateLimit struct {
SpotRate *rate.Limiter
FuturesRate *rate.Limiter
PrivateSpotRate *rate.Limiter
PrivateFeeRate *rate.Limiter
CMFuturesDefaultRate *rate.Limiter
CMFuturesOrderRate *rate.Limiter
CMFuturesOrderListRate *rate.Limiter
@@ -202,131 +207,92 @@ func (r *RateLimit) Limit(ctx context.Context, f request.EndpointLimit) error {
limiter, tokens = r.SpotRate, 1
case privateSpotRate:
limiter, tokens = r.PrivateSpotRate, 1
case privateFeeRate:
limiter, tokens = r.PrivateFeeRate, 1
case cFuturesDefaultRate:
limiter, tokens = r.CMFuturesDefaultRate, 1
case cFuturesCancelActiveOrderRate, cFuturesCreateConditionalOrderRate, cFuturesCancelConditionalOrderRate, cFuturesReplaceActiveOrderRate,
cFuturesReplaceConditionalOrderRate, cFuturesCreateOrderRate:
limiter, tokens = r.CMFuturesOrderRate, 1
case cFuturesCancelAllActiveOrderRate, cFuturesCancelAllConditionalOrderRate:
limiter, tokens = r.CMFuturesOrderRate, 10
case cFuturesGetActiveOrderRate, cFuturesGetConditionalOrderRate, cFuturesGetRealtimeOrderRate:
limiter, tokens = r.CMFuturesOrderListRate, 1
case cFuturesTradeRate:
limiter, tokens = r.CMFuturesExecutionRate, 1
case cFuturesSetLeverageRate, cFuturesUpdateMarginRate, cFuturesSetTradingRate, cFuturesSwitchPositionRate, cFuturesGetTradingFeeRate:
limiter, tokens = r.CMFuturesPositionRate, 1
case cFuturesPositionRate, cFuturesWalletBalanceRate:
limiter, tokens = r.CMFuturesPositionListRate, 1
case cFuturesLastFundingFeeRate, cFuturesPredictFundingRate:
limiter, tokens = r.CMFuturesFundingRate, 1
case cFuturesWalletFundRecordRate, cFuturesWalletWithdrawalRate:
limiter, tokens = r.CMFuturesWalletRate, 1
case cFuturesAPIKeyInfoRate:
limiter, tokens = r.CMFuturesAccountRate, 1
case uFuturesDefaultRate:
limiter, tokens = r.UFuturesDefaultRate, 1
case uFuturesCreateOrderRate, uFuturesCancelOrderRate, uFuturesCreateConditionalOrderRate, uFuturesCancelConditionalOrderRate:
limiter, tokens = r.UFuturesOrderRate, 1
case uFuturesCancelAllOrderRate, uFuturesCancelAllConditionalOrderRate:
limiter, tokens = r.UFuturesOrderRate, 10
case uFuturesSetLeverageRate, uFuturesSwitchMargin, uFuturesSwitchPosition, uFuturesSetMarginRate, uFuturesSetTradingStopRate, uFuturesUpdateMarginRate:
limiter, tokens = r.UFuturesPositionRate, 1
case uFuturesPositionRate, uFuturesGetClosedTradesRate, uFuturesGetTradesRate:
limiter, tokens = r.UFuturesPositionListRate, 1
case uFuturesGetActiveOrderRate, uFuturesGetActiveRealtimeOrderRate, uFuturesGetConditionalOrderRate, uFuturesGetConditionalRealtimeOrderRate:
limiter, tokens = r.UFuturesOrderListRate, 1
case uFuturesGetMyLastFundingFeeRate, uFuturesPredictFundingRate:
limiter, tokens = r.UFuturesFundingRate, 1
case futuresDefaultRate:
limiter, tokens = r.FuturesDefaultRate, 1
case futuresCancelOrderRate, futuresCreateOrderRate, futuresReplaceOrderRate, futuresReplaceConditionalOrderRate, futuresCancelConditionalOrderRate,
futuresCreateConditionalOrderRate:
limiter, tokens = r.FuturesOrderRate, 1
case futuresCancelAllOrderRate, futuresCancelAllConditionalOrderRate:
limiter, tokens = r.FuturesOrderRate, 10
case futuresGetActiveOrderRate, futuresGetConditionalOrderRate, futuresGetActiveRealtimeOrderRate, futuresGetConditionalRealtimeOrderRate:
limiter, tokens = r.FuturesOrderListRate, 1
case futuresGetTradeRate:
limiter, tokens = r.FuturesExecutionRate, 1
case futuresSetLeverageRate, futuresUpdateMarginRate, futuresSetTradingStopRate, futuresSwitchPositionModeRate, futuresSwitchMarginRate, futuresSwitchPositionRate:
limiter, tokens = r.FuturesPositionRate, 1
case futuresPositionRate:
limiter, tokens = r.FuturesPositionListRate, 1
case usdcPublicRate:
limiter, tokens = r.USDCPublic, 1
case usdcCancelAllOrderRate:
limiter, tokens = r.USDCCancelAllOrderRate, 1
case usdcPlaceOrderRate:
limiter, tokens = r.USDCPlaceOrderRate, 1
case usdcModifyOrderRate:
limiter, tokens = r.USDCModifyOrderRate, 1
case usdcCancelOrderRate:
limiter, tokens = r.USDCCancelOrderRate, 1
case usdcGetOrderRate:
limiter, tokens = r.USDCGetOrderRate, 1
case usdcGetOrderHistoryRate:
limiter, tokens = r.USDCGetOrderHistoryRate, 1
case usdcGetTradeHistoryRate:
limiter, tokens = r.USDCGetTradeHistoryRate, 1
case usdcGetTransactionRate:
limiter, tokens = r.USDCGetTransactionRate, 1
case usdcGetWalletRate:
limiter, tokens = r.USDCGetWalletRate, 1
case usdcGetAssetRate:
limiter, tokens = r.USDCGetAssetRate, 1
case usdcGetMarginRate:
limiter, tokens = r.USDCGetMarginRate, 1
case usdcGetPositionRate:
limiter, tokens = r.USDCGetPositionRate, 1
case usdcSetLeverageRate:
limiter, tokens = r.USDCSetLeverageRate, 1
case usdcGetSettlementRate:
limiter, tokens = r.USDCGetSettlementRate, 1
case usdcSetRiskRate:
limiter, tokens = r.USDCSetRiskRate, 1
case usdcGetPredictedFundingRate:
limiter, tokens = r.USDCGetPredictedFundingRate, 1
default:
limiter, tokens = r.SpotRate, 1
}
@@ -360,7 +326,8 @@ func SetRateLimit() *RateLimit {
return &RateLimit{
SpotRate: request.NewRateLimit(spotInterval, spotRequestRate),
FuturesRate: request.NewRateLimit(futuresPublicInterval, futuresRequestRate),
PrivateSpotRate: request.NewRateLimit(spotInterval, spotPrivateRequestRate),
PrivateSpotRate: request.NewRateLimit(spotPrivateInterval, spotPrivateRequestRate),
PrivateFeeRate: request.NewRateLimit(spotPrivateInterval, spotPrivateFeeRequestRate),
CMFuturesDefaultRate: request.NewRateLimit(futuresInterval, futuresDefaultRateCount),
CMFuturesOrderRate: request.NewRateLimit(futuresInterval, futuresOrderRate),
CMFuturesOrderListRate: request.NewRateLimit(futuresInterval, futuresOrderListRate),

View File

@@ -1907,7 +1907,7 @@ func TestUpdateOrderExecutionLimits(t *testing.T) {
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 {
if got := limits.MinimumBaseAmount; got != tt.min {
t.Errorf("Okx UpdateOrderExecutionLimits wrong MinAmount; Pair: %s Expected: %v Got: %v", tt.pair, tt.min, got)
}
}

View File

@@ -342,7 +342,7 @@ func (ok *Okx) UpdateOrderExecutionLimits(ctx context.Context, a asset.Item) err
Pair: pair,
Asset: a,
PriceStepIncrementSize: insts[x].TickSize,
MinAmount: insts[x].MinimumOrderSize,
MinimumBaseAmount: insts[x].MinimumOrderSize,
}
}

View File

@@ -52,6 +52,7 @@ var (
errCannotLoadLimit = errors.New("cannot load limit, levels not supplied")
errInvalidPriceLevels = errors.New("invalid price levels, cannot load limits")
errInvalidAmountLevels = errors.New("invalid amount levels, cannot load limits")
errInvalidQuoteLevels = errors.New("invalid quote levels, cannot load limits")
)
// ExecutionLimits defines minimum and maximum values in relation to
@@ -74,9 +75,12 @@ type MinMaxLevel struct {
MultiplierDown float64
MultiplierDecimal float64
AveragePriceMinutes int64
MinAmount float64
MaxAmount float64
MinimumBaseAmount float64
MaximumBaseAmount float64
MinimumQuoteAmount float64
MaximumQuoteAmount float64
AmountStepIncrementSize float64
QuoteStepIncrementSize float64
MinNotional float64
MaxIcebergParts int64
MarketMinQty float64
@@ -130,15 +134,26 @@ func (e *ExecutionLimits) LoadLimits(levels []MinMaxLevel) error {
levels[x].MaxPrice)
}
if levels[x].MinAmount > 0 &&
levels[x].MaxAmount > 0 &&
levels[x].MinAmount > levels[x].MaxAmount {
if levels[x].MinimumBaseAmount > 0 &&
levels[x].MaximumBaseAmount > 0 &&
levels[x].MinimumBaseAmount > levels[x].MaximumBaseAmount {
return fmt.Errorf("%w for %s %s supplied min: %f max: %f",
errInvalidAmountLevels,
levels[x].Asset,
levels[x].Pair,
levels[x].MinAmount,
levels[x].MaxAmount)
levels[x].MinimumBaseAmount,
levels[x].MaximumBaseAmount)
}
if levels[x].MinimumQuoteAmount > 0 &&
levels[x].MaximumQuoteAmount > 0 &&
levels[x].MinimumQuoteAmount > levels[x].MaximumQuoteAmount {
return fmt.Errorf("%w for %s %s supplied min: %f max: %f",
errInvalidQuoteLevels,
levels[x].Asset,
levels[x].Pair,
levels[x].MinimumQuoteAmount,
levels[x].MaximumQuoteAmount)
}
m2[levels[x].Pair.Quote.Item] = levels[x]
@@ -209,25 +224,26 @@ func (e *ExecutionLimits) CheckOrderExecutionLimits(a asset.Item, cp currency.Pa
// Conforms checks outbound parameters
func (m *MinMaxLevel) Conforms(price, amount float64, orderType Type) error {
// TODO: Update to take in account Quote amounts as well as Base amounts.
if m == nil {
return nil
}
if m.MinAmount != 0 && amount < m.MinAmount {
if m.MinimumBaseAmount != 0 && amount < m.MinimumBaseAmount {
return fmt.Errorf("%w min: %.8f supplied %.8f",
ErrAmountBelowMin,
m.MinAmount,
m.MinimumBaseAmount,
amount)
}
if m.MaxAmount != 0 && amount > m.MaxAmount {
if m.MaximumBaseAmount != 0 && amount > m.MaximumBaseAmount {
return fmt.Errorf("%w min: %.8f supplied %.8f",
ErrAmountExceedsMax,
m.MaxAmount,
m.MaximumBaseAmount,
amount)
}
if m.AmountStepIncrementSize != 0 {
dAmount := decimal.NewFromFloat(amount)
dMinAmount := decimal.NewFromFloat(m.MinAmount)
dMinAmount := decimal.NewFromFloat(m.MaximumBaseAmount)
dStep := decimal.NewFromFloat(m.AmountStepIncrementSize)
if !dAmount.Sub(dMinAmount).Mod(dStep).IsZero() {
return fmt.Errorf("%w stepSize: %.8f supplied %.8f",
@@ -288,7 +304,7 @@ func (m *MinMaxLevel) Conforms(price, amount float64, orderType Type) error {
}
if m.MarketMinQty != 0 &&
m.MinAmount < m.MarketMinQty &&
m.MinimumBaseAmount < m.MarketMinQty &&
amount < m.MarketMinQty {
return fmt.Errorf("%w min: %.8f supplied %.8f",
ErrMarketAmountBelowMin,
@@ -296,7 +312,7 @@ func (m *MinMaxLevel) Conforms(price, amount float64, orderType Type) error {
amount)
}
if m.MarketMaxQty != 0 &&
m.MaxAmount > m.MarketMaxQty &&
m.MaximumBaseAmount > m.MarketMaxQty &&
amount > m.MarketMaxQty {
return fmt.Errorf("%w max: %.8f supplied %.8f",
ErrMarketAmountExceedsMax,

View File

@@ -25,11 +25,11 @@ func TestLoadLimits(t *testing.T) {
invalidAsset := []MinMaxLevel{
{
Pair: btcusd,
MinPrice: 100000,
MaxPrice: 1000000,
MinAmount: 1,
MaxAmount: 10,
Pair: btcusd,
MinPrice: 100000,
MaxPrice: 1000000,
MinimumBaseAmount: 1,
MaximumBaseAmount: 10,
},
}
err = e.LoadLimits(invalidAsset)
@@ -41,11 +41,11 @@ func TestLoadLimits(t *testing.T) {
invalidPairLoading := []MinMaxLevel{
{
Asset: asset.Spot,
MinPrice: 100000,
MaxPrice: 1000000,
MinAmount: 1,
MaxAmount: 10,
Asset: asset.Spot,
MinPrice: 100000,
MaxPrice: 1000000,
MinimumBaseAmount: 1,
MaximumBaseAmount: 10,
},
}
@@ -56,12 +56,12 @@ func TestLoadLimits(t *testing.T) {
newLimits := []MinMaxLevel{
{
Pair: btcusd,
Asset: asset.Spot,
MinPrice: 100000,
MaxPrice: 1000000,
MinAmount: 1,
MaxAmount: 10,
Pair: btcusd,
Asset: asset.Spot,
MinPrice: 100000,
MaxPrice: 1000000,
MinimumBaseAmount: 1,
MaximumBaseAmount: 10,
},
}
@@ -72,12 +72,12 @@ func TestLoadLimits(t *testing.T) {
badLimit := []MinMaxLevel{
{
Pair: btcusd,
Asset: asset.Spot,
MinPrice: 2,
MaxPrice: 1,
MinAmount: 1,
MaxAmount: 10,
Pair: btcusd,
Asset: asset.Spot,
MinPrice: 2,
MaxPrice: 1,
MinimumBaseAmount: 1,
MaximumBaseAmount: 10,
},
}
@@ -88,12 +88,12 @@ func TestLoadLimits(t *testing.T) {
badLimit = []MinMaxLevel{
{
Pair: btcusd,
Asset: asset.Spot,
MinPrice: 1,
MaxPrice: 2,
MinAmount: 10,
MaxAmount: 9,
Pair: btcusd,
Asset: asset.Spot,
MinPrice: 1,
MaxPrice: 2,
MinimumBaseAmount: 10,
MaximumBaseAmount: 9,
},
}
@@ -116,9 +116,9 @@ func TestLoadLimits(t *testing.T) {
noCompare := []MinMaxLevel{
{
Pair: btcusd,
Asset: asset.Spot,
MinAmount: 10,
Pair: btcusd,
Asset: asset.Spot,
MinimumBaseAmount: 10,
},
}
@@ -151,12 +151,12 @@ func TestGetOrderExecutionLimits(t *testing.T) {
newLimits := []MinMaxLevel{
{
Pair: btcusd,
Asset: asset.Spot,
MinPrice: 100000,
MaxPrice: 1000000,
MinAmount: 1,
MaxAmount: 10,
Pair: btcusd,
Asset: asset.Spot,
MinPrice: 100000,
MaxPrice: 1000000,
MinimumBaseAmount: 1,
MaximumBaseAmount: 10,
},
}
@@ -185,8 +185,8 @@ func TestGetOrderExecutionLimits(t *testing.T) {
t.Fatalf("expected error %v but received %v", nil, err)
}
if tt.MaxAmount != newLimits[0].MaxAmount ||
tt.MinAmount != newLimits[0].MinAmount ||
if tt.MaximumBaseAmount != newLimits[0].MaximumBaseAmount ||
tt.MinimumBaseAmount != newLimits[0].MinimumBaseAmount ||
tt.MaxPrice != newLimits[0].MaxPrice ||
tt.MinPrice != newLimits[0].MinPrice {
t.Fatal("unexpected values")
@@ -203,12 +203,12 @@ func TestCheckLimit(t *testing.T) {
newLimits := []MinMaxLevel{
{
Pair: btcusd,
Asset: asset.Spot,
MinPrice: 100000,
MaxPrice: 1000000,
MinAmount: 1,
MaxAmount: 10,
Pair: btcusd,
Asset: asset.Spot,
MinPrice: 100000,
MaxPrice: 1000000,
MinimumBaseAmount: 1,
MaximumBaseAmount: 10,
},
}
@@ -305,8 +305,8 @@ func TestConforms(t *testing.T) {
t.Fatalf("expected error %v but received %v", nil, err)
}
tt.MinAmount = 1
tt.MaxAmount = 10
tt.MinimumBaseAmount = 1
tt.MaximumBaseAmount = 10
tt.MarketMinQty = 1.1
tt.MarketMaxQty = 9.9

View File

@@ -1,6 +1,11 @@
package sharedtestvalues
import (
"bytes"
"fmt"
"os"
"path/filepath"
"regexp"
"strings"
"testing"
"time"
@@ -103,3 +108,42 @@ func SkipTestIfCannotManipulateOrders(t *testing.T, exch exchange.IBotExchange,
func AreAPICredentialsSet(exch exchange.IBotExchange) bool {
return exch.VerifyAPICredentials(exch.GetDefaultCredentials()) == nil
}
// EmptyStringPotentialPattern is a regular expression pattern for a potential
// empty string into float64
var EmptyStringPotentialPattern = `.*float64.*json:"[^"]*,string".*`
// ForceFileStandard will check all files in the current directory for a regular
// expression pattern. If the pattern is found the test will fail.
func ForceFileStandard(t *testing.T, pattern string) error {
t.Helper()
r := regexp.MustCompile(pattern)
root := "." // Specify the root directory to start walking from
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() && strings.HasSuffix(path, ".go") {
fileContents, err := os.ReadFile(path)
if err != nil {
t.Fatalf("Failed to read file: %v", err)
}
lines := bytes.Split(fileContents, []byte("\n"))
for x, line := range lines {
if r.Match(line) {
t.Errorf("File: %s line contains pattern [%s] match with [%s] at line %d", path, pattern, string(line), x+1)
}
}
}
return nil
})
if err != nil {
return fmt.Errorf("failed to walk directory: %w", err)
}
return nil
}

View File

@@ -16,6 +16,8 @@ var (
errInvalidTicker = errors.New("invalid ticker")
errTickerNotFound = errors.New("ticker not found")
errExchangeNameIsEmpty = errors.New("exchange name is empty")
errBidEqualsAsk = errors.New("bid equals ask this is a crossed or locked market")
errBidGreaterThanAsk = errors.New("bid greater than ask this is a crossed or locked market")
)
func init() {
@@ -129,6 +131,27 @@ func ProcessTicker(p *Price) error {
return fmt.Errorf("%s %s", p.ExchangeName, errPairNotSet)
}
if p.Bid != 0 && p.Ask != 0 {
switch {
case p.ExchangeName == "Bitfinex" && p.AssetType == asset.MarginFunding:
// Margin funding books can be crossed see Bitfinex.
default:
if p.Bid == p.Ask {
return fmt.Errorf("%s %s %w",
p.ExchangeName,
p.Pair,
errBidEqualsAsk)
}
if p.Bid > p.Ask {
return fmt.Errorf("%s %s %w",
p.ExchangeName,
p.Pair,
errBidGreaterThanAsk)
}
}
}
if p.AssetType == asset.Empty {
return fmt.Errorf("%s %s %s",
p.ExchangeName,

View File

@@ -281,6 +281,39 @@ func TestProcessTicker(t *testing.T) { // non-appending function to tickers
t.Fatal("TestProcessTicker pair mismatch")
}
err = ProcessTicker(&Price{
ExchangeName: "Bitfinex",
Pair: currency.NewPair(currency.BTC, currency.USD),
AssetType: asset.Margin,
Bid: 1337,
Ask: 1337,
})
if !errors.Is(err, errBidEqualsAsk) {
t.Errorf("received: %v but expected: %v", err, errBidEqualsAsk)
}
err = ProcessTicker(&Price{
ExchangeName: "Bitfinex",
Pair: currency.NewPair(currency.BTC, currency.USD),
AssetType: asset.Margin,
Bid: 1338,
Ask: 1336,
})
if !errors.Is(err, errBidGreaterThanAsk) {
t.Errorf("received: %v but expected: %v", err, errBidGreaterThanAsk)
}
err = ProcessTicker(&Price{
ExchangeName: "Bitfinex",
Pair: currency.NewPair(currency.BTC, currency.USD),
AssetType: asset.MarginFunding,
Bid: 1338,
Ask: 1336,
})
if !errors.Is(err, nil) {
t.Errorf("received: %v but expected: %v", err, nil)
}
// now test for processing a pair with a different quote currency
newPair, err = currency.NewPairFromStrings("BTC", "AUD")
if err != nil {