Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

testing/loadbot: Add moving markets. #2409

Merged
merged 1 commit into from
Aug 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 9 additions & 1 deletion dex/testing/dcrdex/harness.sh
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,14 @@ if [ $ETH_ON -eq 0 ]; then
"epochDuration": ${EPOCH_DURATION},
"marketBuyBuffer": 1.2
},
{
"base": "BTC_simnet",
"quote": "ETH_simnet",
"lotSize": 1000000,
"rateStep": 1000,
"epochDuration": ${EPOCH_DURATION},
"marketBuyBuffer": 1.2
},
{
"base": "DCR_simnet",
"quote": "DEXTT_simnet",
Expand Down Expand Up @@ -355,7 +363,7 @@ adminsrvon=1
adminsrvpass=adminpass
adminsrvaddr=127.0.0.1:16542
bcasttimeout=1m
freecancels=1
# freecancels=1
maxepochcancels=128
inittakerlotlimit=40
abstakerlotlimit=1200
Expand Down
9 changes: 8 additions & 1 deletion dex/testing/dgb/harness.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,17 @@ export DELTA_WALLET_SEED="ehA5EC6mbNvGCJ4HqtjNc822ojnU2bGRLoc3cZipoYFFYT7tYrq4"
export DELTA_ADDRESS="dgbrt1qdgzj8guegzuyfupcvy3vjlpfxpv8rgruqtkndf"
# Signal that the node needs to restart after encrypting wallet
export RESTART_AFTER_ENCRYPT="1"
export NOMINER="1"
# $1 is the node to create with. $2 is the wallet name
export NEW_WALLET_CMD="./\$1 createwallet \$2"
export BLOCKS_TO_MINE=120 # it chokes with high diff if you mine much more, but if you stop at 100, nothing much is mature it seems
export EXTRA_ARGS="-disabledandelion=1 -rpcbind=0.0.0.0 -rpcallowip=0.0.0.0/0 -nodiscover -nodnsseed" # -onlynet=ipv4 -nodiscover

# Background watch mining by default:
# 'export NOMINER="1"' or uncomment this line to disable
#
# TODO: Cannot presently continuously mine on simnet but when we can comment
# this out.
NOMINER="1"

# Run the harness
../btc/base-harness.sh
4 changes: 4 additions & 0 deletions dex/testing/doge/harness.sh
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ SESSION="${SYMBOL}-harness"

SHELL=$(which bash)

# Background watch mining by default:
# 'export NOMINER="1"' or uncomment this line to disable
#NOMINER="1"

################################################################################
# Load prepared wallets.
################################################################################
Expand Down
9 changes: 8 additions & 1 deletion dex/testing/loadbot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ pingpong **traders** in parallel.
The **sidestacker** program runs 2 **traders**, one seller and one buyer. Each
epoch, the **traders** will attempt to create order book depth on their side.
If the book is deep enough already, they will place taker orders targeting
the other side.
the other side. Can be further altered by setting a linear increase
(trending market) or an automatic ascending/descending pattern (sideways market).

#### compound

Expand All @@ -38,6 +39,12 @@ The **heavy** program is like **compound** on steroids. Four
**sidestacker traders** with 6 orders per epoch, and a 5-order per epoch
**sniper**.

#### whale

The **whale** program runs multiple **traders** that randomly push the market in
one direction or the other. Can be run separately with other programs to create
a volatile market.

### Logging

Debug logging can be enabled with the `-debug` flag. Trace logging can be
Expand Down
30 changes: 20 additions & 10 deletions dex/testing/loadbot/compound.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,20 @@ import (
// runCompound runs the 'compound' program, consisting of 2 (5/3) unmetered
// sideStackers, a 1-order sniper, and a pingPonger.
func runCompound() {
go blockEvery2()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-- because we have miners in tmux? Makes sense, but the doge and dgb harnesses are missing miner windows. I'll make a separate issue so it doesn't hold up this PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the one block per 15 min should be sufficient. Leaving it to the harnesses so multiple bots can be run without over mining, especially since this seems to be where the dcr harness gets stuck, with mining calls happening concurrently.

I'll add, should only be a few lines each. Sorry for missing that, I assumed they all had miners now.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dgb was turned off, I wonder if intentional?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dgb was turned off, I wonder if intentional?

Don't recall. @dev-warrior777 is turning it back on in another PR it looks like.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but dgb will never work very well for regtest mining until dgb 8.x series which is on RC2 right now and coming to RC3 soon I am assured.

For 8.x they have a new parameter for the daemon which addresses the regtest mining weakness specifically.

Copy link
Member

@chappjc chappjc Jul 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh duh that's why I disabled it. I even talked to their devs about it. easypow

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

easypow correct
I tested it today doing many loops mining 100 blocks a time.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah, conflicts with @dev-warrior777 If that goes in first I will rebase over it.


var oscillator uint64
var wg sync.WaitGroup
wg.Add(4)
go func() {
defer wg.Done()
runTrader(newSideStacker(true, 5, 3, alpha, false, log.SubLogger("STACKER:0")), "CMPD:STACKER:0")
seller, metered, oscillatorWrite := true, false, true
runTrader(newSideStacker(20, 3, alpha, seller, metered, oscillatorWrite,
&oscillator, log.SubLogger("STACKER:0")), "CMPD:STACKER:0")
}()
go func() {
defer wg.Done()
runTrader(newSideStacker(false, 5, 3, alpha, false, log.SubLogger("STACKER:1")), "CMPD:STACKER:1")
seller, metered, oscillatorWrite := false, false, false
runTrader(newSideStacker(20, 3, alpha, seller, metered, oscillatorWrite,
&oscillator, log.SubLogger("STACKER:1")), "CMPD:STACKER:1")
}()
go func() {
defer wg.Done()
Expand Down Expand Up @@ -59,25 +62,32 @@ func runHeavy() {
}
}

go blockEvery2()

var oscillator uint64
var wg sync.WaitGroup
wg.Add(5)
go func() {
defer wg.Done()
runTrader(newSideStacker(true, 12, 6, alpha, true, log.SubLogger("STACKER:0")), "HEAVY:STACKER:0")
seller, metered, oscillatorWrite := true, false, true
runTrader(newSideStacker(24, 6, alpha, seller, metered, oscillatorWrite,
&oscillator, log.SubLogger("STACKER:0")), "HEAVY:STACKER:0")
}()
go func() {
defer wg.Done()
runTrader(newSideStacker(false, 12, 6, alpha, true, log.SubLogger("STACKER:1")), "HEAVY:STACKER:1")
seller, metered, oscillatorWrite := false, false, false
runTrader(newSideStacker(24, 6, alpha, seller, metered, oscillatorWrite,
&oscillator, log.SubLogger("STACKER:1")), "HEAVY:STACKER:1")
}()
go func() {
defer wg.Done()
runTrader(newSideStacker(true, 8, 4, beta, false, log.SubLogger("STACKER:2")), "HEAVY:STACKER:2")
seller, metered, oscillatorWrite := true, false, false
runTrader(newSideStacker(16, 4, beta, seller, metered, oscillatorWrite,
&oscillator, log.SubLogger("STACKER:2")), "HEAVY:STACKER:2")
}()
go func() {
defer wg.Done()
runTrader(newSideStacker(false, 8, 4, beta, false, log.SubLogger("STACKER:3")), "HEAVY:STACKER:3")
seller, metered, oscillatorWrite := false, false, false
runTrader(newSideStacker(16, 4, beta, seller, metered, oscillatorWrite,
&oscillator, log.SubLogger("STACKER:3")), "HEAVY:STACKER:3")
}()
go func() {
defer wg.Done()
Expand Down
58 changes: 51 additions & 7 deletions dex/testing/loadbot/loadbot.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ const (
dextt = "dextt.eth"
maxOrderLots = 10
ethFeeRate = 200 // gwei
// missedCancelErrStr is part of an error found in dcrdex/server/market/orderrouter.go
// that a cancel order may hit with bad timing but is not a problem.
//
// TODO: Consider returning a separate msgjson error from server for
// this case.
missedCancelErrStr = "target order not known:"
)

var (
Expand All @@ -87,7 +93,7 @@ var (

usr, _ = user.Current()
dextestDir = filepath.Join(usr.HomeDir, "dextest")
botDir = filepath.Join(dextestDir, "loadbot")
botDir = filepath.Join(dextestDir, fmt.Sprintf("loadbot_%d", time.Now().Unix()))
alphaIPCFile = filepath.Join(dextestDir, "eth", "alpha", "node", "geth.ipc")
betaIPCFile = filepath.Join(dextestDir, "eth", "beta", "node", "geth.ipc")

Expand All @@ -102,12 +108,14 @@ var (
epochDuration uint64
lotSize uint64
rateStep uint64
rateShift, rateIncrease int64
conversionFactors = make(map[string]uint64)

ethInitFee = (dexeth.InitGas(1, 0) + dexeth.RefundGas(0)) * ethFeeRate
ethRedeemFee = dexeth.RedeemGas(1, 0) * ethFeeRate
defaultMidGap, marketBuyBuffer float64
keepMidGap bool
ethInitFee = (dexeth.InitGas(1, 0) + dexeth.RefundGas(0)) * ethFeeRate
ethRedeemFee = dexeth.RedeemGas(1, 0) * ethFeeRate
defaultMidGap, marketBuyBuffer, whalePercent float64
keepMidGap, oscillate, randomOsc, ignoreErrors bool
oscInterval, oscStep, whaleFrequency uint64

processesMtx sync.Mutex
processes []*process
Expand Down Expand Up @@ -352,6 +360,14 @@ func run() error {
flag.BoolVar(&trace, "trace", false, "use trace logging")
flag.IntVar(&m, "m", 0, "for compound and sidestacker, m is the number of makers to stack before placing takers")
flag.IntVar(&n, "n", 0, "for compound and sidestacker, n is the number of orders to place per epoch (default 3)")
flag.Int64Var(&rateShift, "rateshift", 0, "for compound and sidestacker, rateShift is applied to every order and increases or decreases price by the chosen shift times the rate step, use to create a market trending in one direction (default 0)")
flag.BoolVar(&oscillate, "oscillate", false, "for compound and sidestacker, whether the price should move up and down inside a window, use to emulate a sideways market (default false)")
flag.BoolVar(&randomOsc, "randomosc", false, "for compound and sidestacker, oscillate more randomly")
flag.Uint64Var(&oscInterval, "oscinterval", 300, "for compound and sidestacker, the number of epochs to take for a full oscillation cycle")
flag.Uint64Var(&oscStep, "oscstep", 50, "for compound and sidestacker, the number of rate step to increase or decrease per epoch")
flag.BoolVar(&ignoreErrors, "ignoreerrors", false, "log and ignore errors rather than the default behavior of stopping loadbot")
flag.Uint64Var(&whaleFrequency, "whalefrequency", 4, "controls the frequency with which the whale \"whales\" after it is ready. To whale is to choose a rate and attempt to buy up the entire book at that price. If frequency is N, the whale will whale an average of 1 out of every N+1 epochs (default 4)")
flag.Float64Var(&whalePercent, "whalepercent", 0.1, "The percent of the current mid gap to whale within. If 0.1 the whale will pick a target price between 0.9 and 1.1 percent of the current mid gap (default 0.1)")
flag.Parse()

if programName == "" {
Expand Down Expand Up @@ -435,6 +451,9 @@ func run() error {
marketBuyBuffer = mkt.MBBuffer
break
}

rateIncrease = int64(rateStep) * rateShift

// Adjust to be comparable to the dcr_btc market.
defaultMidGap = defaultBtcPerDcr * float64(rateStep) / 100

Expand Down Expand Up @@ -464,7 +483,7 @@ func run() error {
if err != nil {
return fmt.Errorf("error creating LoggerMaker: %v", err)
}
log /* global */ = loggerMaker.NewLogger("LOADBOT", dex.LevelInfo)
log /* global */ = loggerMaker.NewLogger("LOADBOT")

log.Infof("Running program %s", programName)

Expand Down Expand Up @@ -534,6 +553,7 @@ func run() error {
if err != nil {
return fmt.Errorf("error creating loadbot directory: %v", err)
}
defer os.RemoveAll(botDir)

// Run any specified network conditions.
var toxics toxiproxy.Toxics
Expand Down Expand Up @@ -651,11 +671,13 @@ func run() error {
case "pingpong4":
runPingPong(4)
case "sidestacker":
runSideStacker(5, 3)
runSideStacker(20, 3)
case "compound":
runCompound()
case "heavy":
runHeavy()
case "whale":
runWhale()
default:
log.Criticalf("program " + programName + " not known")
}
Expand Down Expand Up @@ -698,3 +720,25 @@ func loadNodeConfig(symbol, node string) map[string]string {
}
return cfg
}

func symmetricWalletConfig(numCoins int, midGap uint64) (
minBaseQty, maxBaseQty, minQuoteQty, maxQuoteQty uint64) {

minBaseQty = uint64(maxOrderLots) * uint64(numCoins) * lotSize
minQuoteQty = calc.BaseToQuote(midGap, minBaseQty)
// Ensure enough for registration fees.
minBaseQty += 2e8
minQuoteQty += 2e8
// eth fee estimation calls for more reserves.
// TODO: polygon and tokens
if quoteSymbol == eth {
add := (ethRedeemFee + ethInitFee) * uint64(maxOrderLots)
minQuoteQty += add
}
if baseSymbol == eth {
chappjc marked this conversation as resolved.
Show resolved Hide resolved
add := (ethRedeemFee + ethInitFee) * uint64(maxOrderLots)
minBaseQty += add
}
maxBaseQty, maxQuoteQty = minBaseQty*2, minQuoteQty*2
return
}