mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 23:16:45 +00:00
exchanges/futures: Implement open interest (#1417)
* adds open interest to exchanges * ADDS TESTING YEAH * New endpoints, BTSE, RPCS, cached * slight design change, begin gateio You will need to get cached for each exchange that supports it * gateio, huobi, rpc * fix up kraken, cache retrieval * okx, gateio * finalising all implementations and tests * definitely my final ever commit on this * Well, well, well * final v2 * quick fix of bug * test coverage, assert notempty, test helper Added a new testhelper for currency management because its very annoying in a parallel test setting which wastes so much space otherwise * minimises REST requests for Open Interest * types.Number merge misses * Minimises Kraken REST calls * len change, value -> pointer receiver * further fixup * fixes gateio, batch calculates open interest * single gateio, lint const fixes * rejig and more thorough oi for huobi * formatting expansion * minor fix for handling expiring contracts * rm unused Binance strings * add bybit support, fix bybit issues * oopsie doopsie, dont look at my whoopsie * Fix issue, remove feature * move an irrelevant function for the pr * mini bybit upgrades * fixes cli request bug
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
|
||||
)
|
||||
|
||||
func TestSetupEventManager(t *testing.T) {
|
||||
@@ -299,7 +300,7 @@ func TestCheckEventCondition(t *testing.T) {
|
||||
}
|
||||
m.m.Lock()
|
||||
err = m.checkEventCondition(&m.events[0])
|
||||
if err != nil && !strings.Contains(err.Error(), "no tickers associated") {
|
||||
if err != nil && !errors.Is(err, ticker.ErrNoTickerFound) {
|
||||
t.Error(err)
|
||||
} else if err == nil {
|
||||
t.Error("expected error")
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/common/crypto"
|
||||
"github.com/thrasher-corp/gocryptotrader/common/file"
|
||||
"github.com/thrasher-corp/gocryptotrader/common/file/archive"
|
||||
"github.com/thrasher-corp/gocryptotrader/common/key"
|
||||
"github.com/thrasher-corp/gocryptotrader/common/timeperiods"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/database"
|
||||
@@ -5948,3 +5949,53 @@ func (s *RPCServer) ChangePositionMargin(ctx context.Context, r *gctrpc.ChangePo
|
||||
MarginSide: r.MarginSide,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetOpenInterest fetches the open interest from the exchange
|
||||
func (s *RPCServer) GetOpenInterest(ctx context.Context, r *gctrpc.GetOpenInterestRequest) (*gctrpc.GetOpenInterestResponse, error) {
|
||||
if r == nil {
|
||||
return nil, fmt.Errorf("%w GetOpenInterestRequest", common.ErrNilPointer)
|
||||
}
|
||||
exch, err := s.GetExchangeByName(r.Exchange)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exch.IsEnabled() {
|
||||
return nil, fmt.Errorf("%s %w", r.Exchange, errExchangeNotEnabled)
|
||||
}
|
||||
feat := exch.GetSupportedFeatures()
|
||||
if !feat.FuturesCapabilities.OpenInterest.Supported {
|
||||
return nil, common.ErrFunctionNotSupported
|
||||
}
|
||||
keys := make([]key.PairAsset, len(r.Data))
|
||||
for i := range r.Data {
|
||||
var a asset.Item
|
||||
a, err = asset.New(r.Data[i].Asset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keys[i].Base = currency.NewCode(r.Data[i].Pair.Base).Item
|
||||
keys[i].Quote = currency.NewCode(r.Data[i].Pair.Quote).Item
|
||||
keys[i].Asset = a
|
||||
}
|
||||
|
||||
openInterest, err := exch.GetOpenInterest(ctx, keys...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp := make([]*gctrpc.OpenInterestDataResponse, len(openInterest))
|
||||
for i := range openInterest {
|
||||
resp[i] = &gctrpc.OpenInterestDataResponse{
|
||||
Exchange: openInterest[i].Key.Exchange,
|
||||
Pair: &gctrpc.CurrencyPair{
|
||||
Base: openInterest[i].Key.Base.String(),
|
||||
Quote: openInterest[i].Key.Quote.String(),
|
||||
},
|
||||
Asset: openInterest[i].Key.Asset.String(),
|
||||
OpenInterest: openInterest[i].OpenInterest,
|
||||
}
|
||||
}
|
||||
return &gctrpc.GetOpenInterestResponse{
|
||||
Data: resp,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -15,8 +15,10 @@ import (
|
||||
|
||||
"github.com/gofrs/uuid"
|
||||
"github.com/shopspring/decimal"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/common/convert"
|
||||
"github.com/thrasher-corp/gocryptotrader/common/key"
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/database"
|
||||
@@ -103,6 +105,23 @@ func (f fExchange) SetCollateralMode(_ context.Context, _ asset.Item, _ collater
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f fExchange) GetOpenInterest(_ context.Context, k ...key.PairAsset) ([]futures.OpenInterest, error) {
|
||||
if len(k) > 0 {
|
||||
return []futures.OpenInterest{
|
||||
{
|
||||
Key: key.ExchangePairAsset{
|
||||
Exchange: f.GetName(),
|
||||
Base: k[0].Base,
|
||||
Quote: k[0].Quote,
|
||||
Asset: k[0].Asset,
|
||||
},
|
||||
OpenInterest: 1337,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (f fExchange) GetCollateralMode(_ context.Context, _ asset.Item) (collateral.Mode, error) {
|
||||
return collateral.SingleMode, nil
|
||||
}
|
||||
@@ -4079,3 +4098,44 @@ func TestGetCollateralMode(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOpenInterest(t *testing.T) {
|
||||
t.Parallel()
|
||||
em := NewExchangeManager()
|
||||
exch, err := em.NewExchangeByName("binance")
|
||||
assert.NoError(t, err)
|
||||
|
||||
exch.SetDefaults()
|
||||
b := exch.GetBase()
|
||||
b.Name = fakeExchangeName
|
||||
b.Enabled = true
|
||||
b.CurrencyPairs.Pairs = make(map[asset.Item]*currency.PairStore)
|
||||
b.CurrencyPairs.Pairs[asset.USDTMarginedFutures] = ¤cy.PairStore{
|
||||
AssetEnabled: convert.BoolPtr(true),
|
||||
}
|
||||
|
||||
fakeExchange := fExchange{
|
||||
IBotExchange: exch,
|
||||
}
|
||||
err = em.Add(fakeExchange)
|
||||
assert.NoError(t, err)
|
||||
|
||||
s := RPCServer{Engine: &Engine{ExchangeManager: em}}
|
||||
_, err = s.GetOpenInterest(context.Background(), nil)
|
||||
assert.ErrorIs(t, err, common.ErrNilPointer)
|
||||
|
||||
req := &gctrpc.GetOpenInterestRequest{}
|
||||
_, err = s.GetOpenInterest(context.Background(), req)
|
||||
assert.ErrorIs(t, err, ErrExchangeNameIsEmpty)
|
||||
|
||||
req.Exchange = fakeExchangeName
|
||||
_, err = s.GetOpenInterest(context.Background(), req)
|
||||
assert.NoError(t, err)
|
||||
|
||||
req.Data = append(req.Data, &gctrpc.OpenInterestDataRequest{
|
||||
Asset: asset.USDTMarginedFutures.String(),
|
||||
Pair: &gctrpc.CurrencyPair{Base: currency.BTC.String(), Quote: currency.USDT.String()},
|
||||
})
|
||||
_, err = s.GetOpenInterest(context.Background(), req)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user