Skip to content
This repository has been archived by the owner on Feb 1, 2024. It is now read-only.

Commit

Permalink
Add test for volume filter function (closes #483) (#585)
Browse files Browse the repository at this point in the history
* Initial commit

* Add readability fixes

* Remove dupe tests, change assert
  • Loading branch information
debnil authored Nov 18, 2020
1 parent ad15439 commit d2b1e48
Show file tree
Hide file tree
Showing 2 changed files with 184 additions and 7 deletions.
14 changes: 7 additions & 7 deletions plugins/volumeFilter.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ func (f *volumeFilter) Apply(ops []txnbuild.Operation, sellingOffers []hProtocol
return ops, nil
}

func volumeFilterFn(dailyOTB *VolumeFilterConfig, dailyTBB *VolumeFilterConfig, op *txnbuild.ManageSellOffer, baseAsset hProtocol.Asset, quoteAsset hProtocol.Asset, lp limitParameters) (*txnbuild.ManageSellOffer, error) {
func volumeFilterFn(dailyOTB *VolumeFilterConfig, dailyTBBAccumulator *VolumeFilterConfig, op *txnbuild.ManageSellOffer, baseAsset hProtocol.Asset, quoteAsset hProtocol.Asset, lp limitParameters) (*txnbuild.ManageSellOffer, error) {
isSell, e := utils.IsSelling(baseAsset, quoteAsset, op.Selling, op.Buying)
if e != nil {
return nil, fmt.Errorf("error when running the isSelling check for offer '%+v': %s", *op, e)
Expand All @@ -180,11 +180,11 @@ func volumeFilterFn(dailyOTB *VolumeFilterConfig, dailyTBB *VolumeFilterConfig,
var keepSellingBase bool
var keepSellingQuote bool
if lp.sellBaseAssetCapInBaseUnits != nil {
projectedSoldInBaseUnits := *dailyOTB.SellBaseAssetCapInBaseUnits + *dailyTBB.SellBaseAssetCapInBaseUnits + amountValueUnitsBeingSold
projectedSoldInBaseUnits := *dailyOTB.SellBaseAssetCapInBaseUnits + *dailyTBBAccumulator.SellBaseAssetCapInBaseUnits + amountValueUnitsBeingSold
keepSellingBase = projectedSoldInBaseUnits <= *lp.sellBaseAssetCapInBaseUnits
newAmountString := ""
if lp.mode == volumeFilterModeExact && !keepSellingBase {
newAmount := *lp.sellBaseAssetCapInBaseUnits - *dailyOTB.SellBaseAssetCapInBaseUnits - *dailyTBB.SellBaseAssetCapInBaseUnits
newAmount := *lp.sellBaseAssetCapInBaseUnits - *dailyOTB.SellBaseAssetCapInBaseUnits - *dailyTBBAccumulator.SellBaseAssetCapInBaseUnits
if newAmount > 0 {
newAmountBeingSold = newAmount
opToReturn.Amount = fmt.Sprintf("%.7f", newAmountBeingSold)
Expand All @@ -198,11 +198,11 @@ func volumeFilterFn(dailyOTB *VolumeFilterConfig, dailyTBB *VolumeFilterConfig,
}

if lp.sellBaseAssetCapInQuoteUnits != nil {
projectedSoldInQuoteUnits := *dailyOTB.SellBaseAssetCapInQuoteUnits + *dailyTBB.SellBaseAssetCapInQuoteUnits + (newAmountBeingSold * sellPrice)
projectedSoldInQuoteUnits := *dailyOTB.SellBaseAssetCapInQuoteUnits + *dailyTBBAccumulator.SellBaseAssetCapInQuoteUnits + (newAmountBeingSold * sellPrice)
keepSellingQuote = projectedSoldInQuoteUnits <= *lp.sellBaseAssetCapInQuoteUnits
newAmountString := ""
if lp.mode == volumeFilterModeExact && !keepSellingQuote {
newAmount := (*lp.sellBaseAssetCapInQuoteUnits - *dailyOTB.SellBaseAssetCapInQuoteUnits - *dailyTBB.SellBaseAssetCapInQuoteUnits) / sellPrice
newAmount := (*lp.sellBaseAssetCapInQuoteUnits - *dailyOTB.SellBaseAssetCapInQuoteUnits - *dailyTBBAccumulator.SellBaseAssetCapInQuoteUnits) / sellPrice
if newAmount > 0 {
newAmountBeingSold = newAmount
opToReturn.Amount = fmt.Sprintf("%.7f", newAmountBeingSold)
Expand All @@ -217,8 +217,8 @@ func volumeFilterFn(dailyOTB *VolumeFilterConfig, dailyTBB *VolumeFilterConfig,

if keepSellingBase && keepSellingQuote {
// update the dailyTBB to include the additional amounts so they can be used in the calculation of the next operation
*dailyTBB.SellBaseAssetCapInBaseUnits += newAmountBeingSold
*dailyTBB.SellBaseAssetCapInQuoteUnits += (newAmountBeingSold * sellPrice)
*dailyTBBAccumulator.SellBaseAssetCapInBaseUnits += newAmountBeingSold
*dailyTBBAccumulator.SellBaseAssetCapInQuoteUnits += (newAmountBeingSold * sellPrice)
return opToReturn, nil
}
} else {
Expand Down
177 changes: 177 additions & 0 deletions plugins/volumeFilter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/stellar/kelp/support/utils"

hProtocol "github.com/stellar/go/protocols/horizon"
"github.com/stellar/go/txnbuild"
"github.com/stellar/kelp/model"
"github.com/stretchr/testify/assert"
)
Expand Down Expand Up @@ -145,3 +146,179 @@ func TestMakeFilterVolume(t *testing.T) {
}
}
}

func TestVolumeFilterFn(t *testing.T) {
testCases := []struct {
name string
mode volumeFilterMode
sellBaseCapInBase *float64
sellBaseCapInQuote *float64
otbBase *float64
otbQuote *float64
tbbBase *float64
tbbQuote *float64
inputOp *txnbuild.ManageSellOffer
wantOp *txnbuild.ManageSellOffer
wantTbbBase *float64
wantTbbQuote *float64
}{
{
name: "1. selling, base units sell cap, don't keep selling base, exact mode",
mode: volumeFilterModeExact,
sellBaseCapInBase: pointy.Float64(0.0),
sellBaseCapInQuote: nil,
otbBase: pointy.Float64(0.0),
otbQuote: pointy.Float64(0.0),
tbbBase: pointy.Float64(0.0),
tbbQuote: pointy.Float64(0.0),
inputOp: makeManageSellOffer("2.0", "100.0"),
wantOp: nil,
wantTbbBase: pointy.Float64(0.0),
wantTbbQuote: pointy.Float64(0.0),
},
{
name: "2. selling, base units sell cap, don't keep selling base, ignore mode",
mode: volumeFilterModeIgnore,
sellBaseCapInBase: pointy.Float64(0.0),
sellBaseCapInQuote: nil,
otbBase: pointy.Float64(0.0),
otbQuote: pointy.Float64(0.0),
tbbBase: pointy.Float64(0.0),
tbbQuote: pointy.Float64(0.0),
inputOp: makeManageSellOffer("2.0", "100.0"),
wantOp: nil,
wantTbbBase: pointy.Float64(0.0),
wantTbbQuote: pointy.Float64(0.0),
},
{
name: "3. selling, base units sell cap, keep selling base, exact mode",
mode: volumeFilterModeExact,
sellBaseCapInBase: pointy.Float64(1.0),
sellBaseCapInQuote: nil,
otbBase: pointy.Float64(0.0),
otbQuote: pointy.Float64(0.0),
tbbBase: pointy.Float64(0.0),
tbbQuote: pointy.Float64(0.0),
inputOp: makeManageSellOffer("2.0", "100.0"),
wantOp: makeManageSellOffer("2.0", "1.0000000"),
wantTbbBase: pointy.Float64(1.0),
wantTbbQuote: pointy.Float64(2.0),
},
{
name: "4. selling, base units sell cap, keep selling base, ignore mode",
mode: volumeFilterModeIgnore,
sellBaseCapInBase: pointy.Float64(1.0),
sellBaseCapInQuote: nil,
otbBase: pointy.Float64(0.0),
otbQuote: pointy.Float64(0.0),
tbbBase: pointy.Float64(0.0),
tbbQuote: pointy.Float64(0.0),
inputOp: makeManageSellOffer("2.0", "100.0"),
wantOp: nil,
wantTbbBase: pointy.Float64(0.0),
wantTbbQuote: pointy.Float64(0.0),
},
{
name: "7. selling, quote units sell cap, don't keep selling quote, exact mode",
mode: volumeFilterModeExact,
sellBaseCapInBase: nil,
sellBaseCapInQuote: pointy.Float64(0),
otbBase: pointy.Float64(0.0),
otbQuote: pointy.Float64(0.0),
tbbBase: pointy.Float64(0.0),
tbbQuote: pointy.Float64(0.0),
inputOp: makeManageSellOffer("2.0", "100.0"),
wantOp: nil,
wantTbbBase: pointy.Float64(0.0),
wantTbbQuote: pointy.Float64(0.0),
},
{
name: "8. selling, quote units sell cap, don't keep selling quote, ignore mode",
mode: volumeFilterModeIgnore,
sellBaseCapInBase: nil,
sellBaseCapInQuote: pointy.Float64(0),
otbBase: pointy.Float64(0.0),
otbQuote: pointy.Float64(0.0),
tbbBase: pointy.Float64(0.0),
tbbQuote: pointy.Float64(0.0),
inputOp: makeManageSellOffer("2.0", "100.0"),
wantOp: nil,
wantTbbBase: pointy.Float64(0.0),
wantTbbQuote: pointy.Float64(0.0),
},
{
name: "9. selling, quote units sell cap, keep selling quote, exact mode",
mode: volumeFilterModeExact,
sellBaseCapInBase: nil,
sellBaseCapInQuote: pointy.Float64(1.0),
otbBase: pointy.Float64(0.0),
otbQuote: pointy.Float64(0.0),
tbbBase: pointy.Float64(0.0),
tbbQuote: pointy.Float64(0.0),
inputOp: makeManageSellOffer("2.0", "100.0"),
wantOp: makeManageSellOffer("2.0", "0.5000000"),
wantTbbBase: pointy.Float64(0.5),
wantTbbQuote: pointy.Float64(1.0),
},
{
name: "10. selling, quote units sell cap, keep selling quote, ignore mode",
mode: volumeFilterModeIgnore,
sellBaseCapInBase: nil,
sellBaseCapInQuote: pointy.Float64(1.0),
otbBase: pointy.Float64(0.0),
otbQuote: pointy.Float64(0.0),
tbbBase: pointy.Float64(0.0),
tbbQuote: pointy.Float64(0.0),
inputOp: makeManageSellOffer("2.0", "100.0"),
wantOp: nil,
wantTbbBase: pointy.Float64(0.0),
wantTbbQuote: pointy.Float64(0.0),
},
}

// we fix the marketIDs and accountIDs, since volumeFilterFn output does not depend on them
marketIDs := []string{}
accountIDs := []string{}

for _, k := range testCases {
t.Run(k.name, func(t *testing.T) {
// exactly one of the two cap values must be set
if k.sellBaseCapInBase == nil && k.sellBaseCapInQuote == nil {
assert.Fail(t, "either one of the two cap values must be set")
return
}

if k.sellBaseCapInBase != nil && k.sellBaseCapInQuote != nil {
assert.Fail(t, "both of the cap values cannot be set")
return
}

dailyOTB := makeRawVolumeFilterConfig(k.otbBase, k.otbQuote, k.mode, marketIDs, accountIDs)
dailyTBBAccumulator := makeRawVolumeFilterConfig(k.tbbBase, k.tbbQuote, k.mode, marketIDs, accountIDs)
lp := limitParameters{
sellBaseAssetCapInBaseUnits: k.sellBaseCapInBase,
sellBaseAssetCapInQuoteUnits: k.sellBaseCapInQuote,
mode: k.mode,
}

actual, e := volumeFilterFn(dailyOTB, dailyTBBAccumulator, k.inputOp, utils.NativeAsset, utils.NativeAsset, lp)
if !assert.Nil(t, e) {
return
}
assert.Equal(t, k.wantOp, actual)

wantTBBAccumulator := makeRawVolumeFilterConfig(k.wantTbbBase, k.wantTbbQuote, k.mode, marketIDs, accountIDs)
assert.Equal(t, wantTBBAccumulator, dailyTBBAccumulator)
})

}
}

func makeManageSellOffer(price string, amount string) *txnbuild.ManageSellOffer {
return &txnbuild.ManageSellOffer{
Buying: txnbuild.NativeAsset{},
Selling: txnbuild.NativeAsset{},
Price: price,
Amount: amount,
}
}

0 comments on commit d2b1e48

Please sign in to comment.