exchange/order/limits: Migrate to new package and integrate with exchanges (#1860)

* move limits, transition to key gen

* rollout NewExchangePairAssetKey everywhere

* test improvements

* self-review fixes

* ok, lets go

* fix merge issue

* slower value func,assertify,drop IsValidPairString

* remove binance reference for backtesting test

* Redundant nil checks removed due to redundancy

* Update order_test.go

* Move limits back into /exchanges/

* puts limits in a different box again

* SHAZBERT SPECIAL SUGGESTIONS

* Update gateio_wrapper.go

* fixes all build issues

* Many niteroos!

* something has gone awry

* bugfix

* gk's everywhere nits

* lint

* extra lint

* re-remove IsValidPairString

* lint fix

* standardise test

* revert some bads

* dupe rm

* another revert 360 mcgee

* un-in-revertify

* Update exchange/order/limits/levels_test.go

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

* fix

* Update exchanges/binance/binance_test.go

HERE'S HOPING GITHUB FORMATS THIS CORRECTLY!

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

* update text

* rn func, same line err gk4202000

---------

Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>
Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com>
This commit is contained in:
Scott
2025-08-26 12:30:21 +10:00
committed by GitHub
parent fc0f262c42
commit 85403fe801
103 changed files with 1751 additions and 2168 deletions

View File

@@ -21,7 +21,7 @@ import (
// to track futures orders
func SetupPositionController() PositionController {
return PositionController{
multiPositionTrackers: make(map[key.ExchangePairAsset]*MultiPositionTracker),
multiPositionTrackers: make(map[key.ExchangeAssetPair]*MultiPositionTracker),
}
}
@@ -42,12 +42,7 @@ func (c *PositionController) TrackNewOrder(d *order.Detail) error {
}
c.m.Lock()
defer c.m.Unlock()
exchMap, ok := c.multiPositionTrackers[key.ExchangePairAsset{
Exchange: d.Exchange,
Base: d.Pair.Base.Item,
Quote: d.Pair.Quote.Item,
Asset: d.AssetType,
}]
exchMap, ok := c.multiPositionTrackers[key.NewExchangeAssetPair(d.Exchange, d.AssetType, d.Pair)]
if !ok {
exchMap, err = SetupMultiPositionTracker(&MultiPositionTrackerSetup{
Exchange: d.Exchange,
@@ -58,12 +53,7 @@ func (c *PositionController) TrackNewOrder(d *order.Detail) error {
if err != nil {
return err
}
c.multiPositionTrackers[key.ExchangePairAsset{
Exchange: d.Exchange,
Base: d.Pair.Base.Item,
Quote: d.Pair.Quote.Item,
Asset: d.AssetType,
}] = exchMap
c.multiPositionTrackers[key.NewExchangeAssetPair(d.Exchange, d.AssetType, d.Pair)] = exchMap
}
err = exchMap.TrackNewOrder(d)
if err != nil {
@@ -87,12 +77,7 @@ func (c *PositionController) SetCollateralCurrency(exch string, item asset.Item,
c.m.Lock()
defer c.m.Unlock()
tracker := c.multiPositionTrackers[key.ExchangePairAsset{
Exchange: exch,
Base: pair.Base.Item,
Quote: pair.Quote.Item,
Asset: item,
}]
tracker := c.multiPositionTrackers[key.NewExchangeAssetPair(exch, item, pair)]
if tracker == nil {
return fmt.Errorf("%w no open position for %v %v %v", ErrPositionNotFound, exch, item, pair)
}
@@ -120,12 +105,7 @@ func (c *PositionController) GetPositionsForExchange(exch string, item asset.Ite
}
c.m.Lock()
defer c.m.Unlock()
tracker := c.multiPositionTrackers[key.ExchangePairAsset{
Exchange: exch,
Base: pair.Base.Item,
Quote: pair.Quote.Item,
Asset: item,
}]
tracker := c.multiPositionTrackers[key.NewExchangeAssetPair(exch, item, pair)]
if tracker == nil {
return nil, fmt.Errorf("%w no open position for %v %v %v", ErrPositionNotFound, exch, item, pair)
}
@@ -148,12 +128,7 @@ func (c *PositionController) TrackFundingDetails(d *fundingrate.HistoricalRates)
}
c.m.Lock()
defer c.m.Unlock()
tracker := c.multiPositionTrackers[key.ExchangePairAsset{
Exchange: d.Exchange,
Base: d.Pair.Base.Item,
Quote: d.Pair.Quote.Item,
Asset: d.Asset,
}]
tracker := c.multiPositionTrackers[key.NewExchangeAssetPair(d.Exchange, d.Asset, d.Pair)]
if tracker == nil {
return fmt.Errorf("%w no open position for %v %v %v", ErrPositionNotFound, d.Exchange, d.Asset, d.Pair)
}
@@ -188,12 +163,7 @@ func (c *PositionController) GetOpenPosition(exch string, item asset.Item, pair
}
c.m.Lock()
defer c.m.Unlock()
tracker := c.multiPositionTrackers[key.ExchangePairAsset{
Exchange: exch,
Base: pair.Base.Item,
Quote: pair.Quote.Item,
Asset: item,
}]
tracker := c.multiPositionTrackers[key.NewExchangeAssetPair(exch, item, pair)]
if tracker == nil {
return nil, fmt.Errorf("%w no open position for %v %v %v", ErrPositionNotFound, exch, item, pair)
}
@@ -245,12 +215,7 @@ func (c *PositionController) UpdateOpenPositionUnrealisedPNL(exch string, item a
}
c.m.Lock()
defer c.m.Unlock()
tracker := c.multiPositionTrackers[key.ExchangePairAsset{
Exchange: exch,
Base: pair.Base.Item,
Quote: pair.Quote.Item,
Asset: item,
}]
tracker := c.multiPositionTrackers[key.NewExchangeAssetPair(exch, item, pair)]
if tracker == nil {
return decimal.Zero, fmt.Errorf("%v %v %v %w", exch, item, pair, ErrPositionNotFound)
}
@@ -342,12 +307,7 @@ func (c *PositionController) ClearPositionsForExchange(exch string, item asset.I
c.m.Lock()
defer c.m.Unlock()
tracker := c.multiPositionTrackers[key.ExchangePairAsset{
Exchange: exch,
Base: pair.Base.Item,
Quote: pair.Quote.Item,
Asset: item,
}]
tracker := c.multiPositionTrackers[key.NewExchangeAssetPair(exch, item, pair)]
if tracker == nil {
return fmt.Errorf("%v %v %v %w", exch, item, pair, ErrPositionNotFound)
}
@@ -365,12 +325,7 @@ func (c *PositionController) ClearPositionsForExchange(exch string, item asset.I
if err != nil {
return err
}
c.multiPositionTrackers[key.ExchangePairAsset{
Exchange: exch,
Base: pair.Base.Item,
Quote: pair.Quote.Item,
Asset: item,
}] = newMPT
c.multiPositionTrackers[key.NewExchangeAssetPair(exch, item, pair)] = newMPT
return nil
}

View File

@@ -532,34 +532,19 @@ func TestGetPositionsForExchange(t *testing.T) {
if len(pos) != 0 {
t.Error("expected zero")
}
c.multiPositionTrackers = make(map[key.ExchangePairAsset]*MultiPositionTracker)
c.multiPositionTrackers[key.ExchangePairAsset{
Exchange: testExchange,
Base: p.Base.Item,
Quote: p.Quote.Item,
Asset: asset.Futures,
}] = nil
c.multiPositionTrackers = make(map[key.ExchangeAssetPair]*MultiPositionTracker)
c.multiPositionTrackers[key.NewExchangeAssetPair(testExchange, asset.Futures, p)] = nil
_, err = c.GetPositionsForExchange(testExchange, asset.Futures, p)
assert.ErrorIs(t, err, ErrPositionNotFound)
require.ErrorIs(t, err, ErrPositionNotFound, "GetPositionsForExchange must return ErrPositionNotFound")
c.multiPositionTrackers[key.ExchangePairAsset{
Exchange: testExchange,
Base: p.Base.Item,
Quote: p.Quote.Item,
Asset: asset.Futures,
}] = nil
c.multiPositionTrackers[key.NewExchangeAssetPair(testExchange, asset.Futures, p)] = nil
_, err = c.GetPositionsForExchange(testExchange, asset.Futures, p)
assert.ErrorIs(t, err, ErrPositionNotFound)
_, err = c.GetPositionsForExchange(testExchange, asset.Spot, p)
assert.ErrorIs(t, err, ErrNotFuturesAsset)
c.multiPositionTrackers[key.ExchangePairAsset{
Exchange: testExchange,
Base: p.Base.Item,
Quote: p.Quote.Item,
Asset: asset.Futures,
}] = &MultiPositionTracker{
c.multiPositionTrackers[key.NewExchangeAssetPair(testExchange, asset.Futures, p)] = &MultiPositionTracker{
exchange: testExchange,
}
@@ -569,12 +554,7 @@ func TestGetPositionsForExchange(t *testing.T) {
if len(pos) != 0 {
t.Fatal("expected zero")
}
c.multiPositionTrackers[key.ExchangePairAsset{
Exchange: testExchange,
Base: p.Base.Item,
Quote: p.Quote.Item,
Asset: asset.Futures,
}] = &MultiPositionTracker{
c.multiPositionTrackers[key.NewExchangeAssetPair(testExchange, asset.Futures, p)] = &MultiPositionTracker{
exchange: testExchange,
positions: []*PositionTracker{
{
@@ -606,19 +586,14 @@ func TestClearPositionsForExchange(t *testing.T) {
err = c.ClearPositionsForExchange(testExchange, asset.Futures, p)
assert.ErrorIs(t, err, ErrPositionNotFound)
c.multiPositionTrackers = make(map[key.ExchangePairAsset]*MultiPositionTracker)
c.multiPositionTrackers = make(map[key.ExchangeAssetPair]*MultiPositionTracker)
err = c.ClearPositionsForExchange(testExchange, asset.Futures, p)
assert.ErrorIs(t, err, ErrPositionNotFound)
err = c.ClearPositionsForExchange(testExchange, asset.Spot, p)
assert.ErrorIs(t, err, ErrNotFuturesAsset)
c.multiPositionTrackers[key.ExchangePairAsset{
Exchange: testExchange,
Base: p.Base.Item,
Quote: p.Quote.Item,
Asset: asset.Futures,
}] = &MultiPositionTracker{
c.multiPositionTrackers[key.NewExchangeAssetPair(testExchange, asset.Futures, p)] = &MultiPositionTracker{
exchange: testExchange,
underlying: currency.DOGE,
positions: []*PositionTracker{
@@ -628,14 +603,8 @@ func TestClearPositionsForExchange(t *testing.T) {
},
}
err = c.ClearPositionsForExchange(testExchange, asset.Futures, p)
assert.NoError(t, err)
if len(c.multiPositionTrackers[key.ExchangePairAsset{
Exchange: testExchange,
Base: p.Base.Item,
Quote: p.Quote.Item,
Asset: asset.Futures,
}].positions) != 0 {
require.NoError(t, err, "ClearPositionsForExchange must not error")
if len(c.multiPositionTrackers[key.NewExchangeAssetPair(testExchange, asset.Futures, p)].positions) != 0 {
t.Fatal("expected 0")
}
c = nil
@@ -840,20 +809,14 @@ func TestSetCollateralCurrency(t *testing.T) {
assert.ErrorIs(t, err, ErrNotFuturesAsset)
p := currency.NewBTCUSDT()
pc.multiPositionTrackers = make(map[key.ExchangePairAsset]*MultiPositionTracker)
pc.multiPositionTrackers = make(map[key.ExchangeAssetPair]*MultiPositionTracker)
err = pc.SetCollateralCurrency("hi", asset.Futures, p, currency.DOGE)
require.ErrorIs(t, err, ErrPositionNotFound)
err = pc.SetCollateralCurrency("hi", asset.Futures, p, currency.DOGE)
require.ErrorIs(t, err, ErrPositionNotFound)
mapKey := key.ExchangePairAsset{
Exchange: "hi",
Base: p.Base.Item,
Quote: p.Quote.Item,
Asset: asset.Futures,
}
mapKey := key.NewExchangeAssetPair("hi", asset.Futures, p)
pc.multiPositionTrackers[mapKey] = &MultiPositionTracker{
exchange: "hi",
asset: asset.Futures,
@@ -904,13 +867,7 @@ func TestMPTUpdateOpenPositionUnrealisedPNL(t *testing.T) {
})
require.NoError(t, err)
mapKey := key.ExchangePairAsset{
Exchange: "hi",
Base: p.Base.Item,
Quote: p.Quote.Item,
Asset: asset.Futures,
}
mapKey := key.NewExchangeAssetPair("hi", asset.Futures, p)
result, err := pc.multiPositionTrackers[mapKey].UpdateOpenPositionUnrealisedPNL(1337, time.Now())
require.NoError(t, err)
@@ -1125,13 +1082,7 @@ func TestPCTrackFundingDetails(t *testing.T) {
},
}
mapKey := key.ExchangePairAsset{
Exchange: testExchange,
Base: p.Base.Item,
Quote: p.Quote.Item,
Asset: asset.Futures,
}
mapKey := key.NewExchangeAssetPair(testExchange, asset.Futures, p)
pc.multiPositionTrackers[mapKey].orderPositions["lol"].openingDate = tn.Add(-time.Hour)
pc.multiPositionTrackers[mapKey].orderPositions["lol"].lastUpdated = tn
err = pc.TrackFundingDetails(rates)

View File

@@ -86,7 +86,7 @@ type TotalCollateralResponse struct {
// the position controller and its all tracked happily
type PositionController struct {
m sync.Mutex
multiPositionTrackers map[key.ExchangePairAsset]*MultiPositionTracker
multiPositionTrackers map[key.ExchangeAssetPair]*MultiPositionTracker
updated time.Time
}
@@ -201,7 +201,7 @@ type CollateralCalculator struct {
// OpenInterest holds open interest data for an exchange pair asset
type OpenInterest struct {
Key key.ExchangePairAsset
Key key.ExchangeAssetPair
OpenInterest float64
}