From 5206fcd1bc81494d4034d69142f88540af9dc289 Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Tue, 23 Apr 2024 03:35:22 +1000 Subject: [PATCH 01/34] docs: make it more clear that a MNEMONIC is required to run the script --- README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ab18c7b..88a1ef9 100644 --- a/README.md +++ b/README.md @@ -12,18 +12,24 @@ locally this should be a single dockerized neutron node - `make build-neutron` To run the default setup of a single neutron-node chain and a single trading bot: -- `make start-trade-bot` +- `make start-trade-bot MNEMONIC=...` +- at least a single mnenomic must be specified from the mnenomics listed in the options section below + - `MNEMONIC` + - `MNEMONICS` + - `BOT_MNEMONIC` + - `BOT_MNEMONICS` + - `FAUCET_MNEMONIC` This composed neutron chain and trading bot network will persist until you call: - `make stop-trade-bot` ### Test runs (start+stop) You can test a chain and bot(s) configuration and exit with cleanup in one step using: -- `make test-trade-bot` +- `make test-trade-bot MNEMONIC=...` However the default settings are quite conservative, and won't product many txs. A larger test which should generate approximately ~1000-2000 txs in ~6 minutes with 30 bots could be done with: -- `make test-trade-bot BOTS=30 BOT_RAMPING_DELAY=5 TRADE_FREQUENCY_SECONDS=0 TRADE_DURATION_SECONDS=180` +- `make test-trade-bot BOTS=30 BOT_RAMPING_DELAY=5 TRADE_FREQUENCY_SECONDS=0 TRADE_DURATION_SECONDS=180 MNEMONIC=...` This can be ideal for CI type testing of a service that depends on Dex transactions on a Neutron chain. But if you want the chain to persist after the trades are completed (with a finite `TRADE_DURATION_SECONDS`), From 02262a45c495cf07432b77e6e93570b9db4bed5f Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Tue, 23 Apr 2024 03:48:37 +1000 Subject: [PATCH 02/34] docs: explain the local demo mnemonics source twice --- README.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/README.md b/README.md index 88a1ef9..5873806 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ To run the default setup of a single neutron-node chain and a single trading bot - `BOT_MNEMONIC` - `BOT_MNEMONICS` - `FAUCET_MNEMONIC` + - if running a local chain you can use DEMO_MNEMONICs from the neutron repo [networks/init.sh](https://github.com/neutron-org/neutron/blob/v3.0.0/network/init.sh#L19-L21) file This composed neutron chain and trading bot network will persist until you call: - `make stop-trade-bot` @@ -55,11 +56,6 @@ All docker-compose env vars are able to be set in both `make start-trade-bot` an - `GAS_PRICES`: calculate how many fees to pay from this fraction of gas - `TOKEN_CONFIG`: a token pairs configuration (JSON) object for eg. token amounts to trade - see [helpers.sh](https://github.com/neutron-org/dex-trading-bot/blob/131a5f1590483840305cb475f8a867996509333e/scripts/helpers.sh#L41-L63) for more setting details - - mnemonics: - - `FAUCET_MNEMONIC` (optional): the mnemonic of the account that will fund generated bots - - `BOT_MNEMONIC/S` or `MNEMONIC/S` (optional): the mnemonics for self-funded bot account(s) - - at least one of `FAUCET_MNEMONIC` or `BOT_/MNEMONIC/S` should be provided - - with a local chain you can use `DEMO_MNEMONIC`s from the neutron networks/init.sh file - `COINGECKO_API_TOKEN`: a Coingecko API token used for live prices fetching. Only used with respective token pair price setting. The token should be a [demo API token](https://www.coingecko.com/en/api/pricing). Pro tokens aren't supported because they use different endpoints. Keep in mind the very limited request rate the demo tokens provide when configuring the bots number and trading intensity. eg. `make start-trade-bot BOTS=30 BOT_RAMPING_DELAY=5 TRADE_FREQUENCY_SECONDS=0 TRADE_DURATION_SECONDS=450 MNEMONIC=...` From 1c464bdfbbaa1f983ed32a93630108a9e8d2ad78 Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Thu, 25 Apr 2024 22:08:59 +1000 Subject: [PATCH 03/34] docs: move mnenomic option documentation to one section --- README.md | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 5873806..d2d5795 100644 --- a/README.md +++ b/README.md @@ -11,15 +11,9 @@ To run the bot, you will first need a chain to run the bot against, locally this should be a single dockerized neutron node - `make build-neutron` -To run the default setup of a single neutron-node chain and a single trading bot: +To run the default setup of a single neutron-node chain and a single trading bot with a single wallet: - `make start-trade-bot MNEMONIC=...` -- at least a single mnenomic must be specified from the mnenomics listed in the options section below - - `MNEMONIC` - - `MNEMONICS` - - `BOT_MNEMONIC` - - `BOT_MNEMONICS` - - `FAUCET_MNEMONIC` - - if running a local chain you can use DEMO_MNEMONICs from the neutron repo [networks/init.sh](https://github.com/neutron-org/neutron/blob/v3.0.0/network/init.sh#L19-L21) file +- the available `MNENOMIC` options are explained in the [Options section](#mnemonic-options) This composed neutron chain and trading bot network will persist until you call: - `make stop-trade-bot` @@ -38,6 +32,19 @@ then `make start-trade-bot` should be used instead. ## Available options +### Mnemonic options +A single mnenomic option must be specified to run `make start-trade-bot` or `make test-trade-bot` this may be in the form of: +- a list of mnemonics to be used (delimited with any `\r\n,;` characters) where one mnemonic is given to each bot (in series). An error will be thrown if not enough mnemonics are provided for the number of `BOTS` requested. + - `MNEMONIC` + - `MNEMONICS` + - `BOT_MNEMONIC` + - `BOT_MNEMONICS` +- a single mnenomic which will be used to like a faucet to fund a separate randomly generated wallet for each bot requested (so you may easily run more than one bot with one wallet). + - `FAUCET_MNEMONIC` +- if you are running a local chain you can use the DEMO_MNEMONICs from the neutron repo [networks/init.sh](https://github.com/neutron-org/neutron/blob/v3.0.0/network/init.sh#L19-L21) file for these settings. + +### Optional options + All docker-compose env vars are able to be set in both `make start-trade-bot` and `make test-trade-bot` - Chain variables - `CHAIN_ID`: the chain ID From 935c7008f2bdfd6cfcfa3fb87f5e451187cdfd1b Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Thu, 25 Apr 2024 22:15:56 +1000 Subject: [PATCH 04/34] docs: explain the behavior of using FAUCET_MNEMONIC at simulation end --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d2d5795..6c13797 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,8 @@ A single mnenomic option must be specified to run `make start-trade-bot` or `mak - `BOT_MNEMONICS` - a single mnenomic which will be used to like a faucet to fund a separate randomly generated wallet for each bot requested (so you may easily run more than one bot with one wallet). - `FAUCET_MNEMONIC` + - on simulation end: the remaining token balance will be refunded to the faucet wallet. + - you should strongly consider using `ON_EXIT_WITHDRAW_POOLS=1` when using this option on a testnet. If the pools are not withdrawn after the simulation and you have not recorded the randomly generated mnenomics for each bot: then ***you will lose access to these deposited tokens***. - if you are running a local chain you can use the DEMO_MNEMONICs from the neutron repo [networks/init.sh](https://github.com/neutron-org/neutron/blob/v3.0.0/network/init.sh#L19-L21) file for these settings. ### Optional options From e9aa7360fcf09d6ffbb10a0bc95c86904d22e4cf Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Thu, 25 Apr 2024 22:22:57 +1000 Subject: [PATCH 05/34] docs: shorten line lengths to under 120 characters --- README.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 6c13797..75c57dd 100644 --- a/README.md +++ b/README.md @@ -33,17 +33,22 @@ then `make start-trade-bot` should be used instead. ## Available options ### Mnemonic options -A single mnenomic option must be specified to run `make start-trade-bot` or `make test-trade-bot` this may be in the form of: -- a list of mnemonics to be used (delimited with any `\r\n,;` characters) where one mnemonic is given to each bot (in series). An error will be thrown if not enough mnemonics are provided for the number of `BOTS` requested. +A single mnenomic option must be used to run `make start-trade-bot` or `make test-trade-bot` this may be in the form of: +- a list of mnemonics to be used (delimited with any `\r\n,;` characters) where one mnemonic is given to each bot. +An error will be thrown if not enough mnemonics are provided for the number of `BOTS` requested. - `MNEMONIC` - `MNEMONICS` - `BOT_MNEMONIC` - `BOT_MNEMONICS` -- a single mnenomic which will be used to like a faucet to fund a separate randomly generated wallet for each bot requested (so you may easily run more than one bot with one wallet). +- a single mnenomic which will be used to like a faucet to fund a separate randomly generated wallet for each bot +(so you may easily run more than one bot with one wallet). - `FAUCET_MNEMONIC` - on simulation end: the remaining token balance will be refunded to the faucet wallet. - - you should strongly consider using `ON_EXIT_WITHDRAW_POOLS=1` when using this option on a testnet. If the pools are not withdrawn after the simulation and you have not recorded the randomly generated mnenomics for each bot: then ***you will lose access to these deposited tokens***. -- if you are running a local chain you can use the DEMO_MNEMONICs from the neutron repo [networks/init.sh](https://github.com/neutron-org/neutron/blob/v3.0.0/network/init.sh#L19-L21) file for these settings. + - you should strongly consider using `ON_EXIT_WITHDRAW_POOLS=1` when using this option on a testnet. + If the pools are not withdrawn and you have not saved the randomly generated mnenomics for each bot + then ***you will lose access to these deposited tokens***. +- if you are running a local chain you can use the DEMO_MNEMONICs from the neutron repo +[networks/init.sh](https://github.com/neutron-org/neutron/blob/v3.0.0/network/init.sh#L19-L21) file for these settings. ### Optional options From 15d9165ab10e7510ae8e1a80b02c853af4d7307b Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Thu, 25 Apr 2024 22:53:17 +1000 Subject: [PATCH 06/34] docs: move TOKEN_CONFIG and PAIR_CONFIG docs to README file --- README.md | 57 ++++++++++++++++++++++++++++++++++++++++++++-- scripts/helpers.sh | 29 ++++------------------- 2 files changed, 60 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 75c57dd..040b9a9 100644 --- a/README.md +++ b/README.md @@ -68,13 +68,66 @@ All docker-compose env vars are able to be set in both `make start-trade-bot` an - `ON_EXIT_WITHDRAW_POOLS`: if set, withdraw all user's Dex pools after TRADE_DURATION_SECONDS - `GAS_ADJUSTMENT`: how much more than the base estimated gas price to pay for each tx - `GAS_PRICES`: calculate how many fees to pay from this fraction of gas - - `TOKEN_CONFIG`: a token pairs configuration (JSON) object for eg. token amounts to trade - - see [helpers.sh](https://github.com/neutron-org/dex-trading-bot/blob/131a5f1590483840305cb475f8a867996509333e/scripts/helpers.sh#L41-L63) for more setting details + - `TOKEN_CONFIG`: a token pairs configuration (JSON) object to specify trading behavior to use for each token pair + - see the [TOKEN_CONFIG option section](#token_config-option) for more details - `COINGECKO_API_TOKEN`: a Coingecko API token used for live prices fetching. Only used with respective token pair price setting. The token should be a [demo API token](https://www.coingecko.com/en/api/pricing). Pro tokens aren't supported because they use different endpoints. Keep in mind the very limited request rate the demo tokens provide when configuring the bots number and trading intensity. eg. `make start-trade-bot BOTS=30 BOT_RAMPING_DELAY=5 TRADE_FREQUENCY_SECONDS=0 TRADE_DURATION_SECONDS=450 MNEMONIC=...` will start a persistent chain that for the first ~10min (7min+ramping) will generate ~5000txs using 30 bots. +#### TOKEN_CONFIG option + +format for TOKEN_CONFIG is: +``` +TOKEN_CONFIG = { + "amountAtokenA<>amountBtokenB": numeric_price_or_PAIR_CONFIG_object, + "defaults": PAIR_CONFIG +} +``` +the object keys are the usable tokens for each pair (to be shared across all bots), +the object values are the price ratio of tokenB/tokenA, a coingecko pair or a config object: (default values are listed) +``` +PAIR_CONFIG = { + "price": 1, # price ratio is of tokenB/tokenA (how many tokenA is required to buy 1 tokenB?), OR + "price": "coingecko:api_idA<>api_idB", # for live price retrieval, use the coingecko API IDs of the tokens (e.g. "coingecko:cosmos<>neutron-3" for atom<>ntrn pair) + "ticks": 100, # number of ticks for each bot to deposit + "fees": [1, 5, 20, 100] # each LP deposit fee may be (randomly) one of the whitelisted fees here + "gas": "0untrn" # additional gas tokens that bots can use to cover gas fees + "rebalance_factor": 0.5, # fraction of excessive deposits on either pair side to rebalance on each trade + "deposit_factor": 0.5, # fraction of the recommended maximum reserves to use on a single tick deposit + "swap_factor": 0.5, # max fraction of a bot's token reserves to use on a single swap trade (max: 1) + "swap_accuracy": 100, # ~1% of price: swaps will target within ~1% of current price + "deposit_accuracy": 1000, # ~10% of price: deposits will target within ~10% of current price + "amplitude1": 5000, # ~50% of price: current price will vary by ~50% of set price ratio + "period1": 36000, # ten hours: current price will cycle min->max->min every ten hours + "amplitude2": 1000, # ~10% of price: current price will vary by an additional ~10% of price ratio + "period2": 600, # ten minutes: current price will cycle amplitude2 offset every ten minutes +} +``` + +For example the following `TOKEN_CONFIG` option sets each bot to trade on 3 pools +- the first `uibcusdc<>uibcatom` with all default options except price of `1uibcatom = 10uibcusdc` +- the second `untrn<>uibcusdc` with custom GoinGecko pricing and specified 50 deposited ticks +- the third `untrn<>uibcatom` with custom sinusoidal pricing around a price of `1uibcatom = 5untrn` +- all pools will operate with the specified `defaults` values of `fees` and `gas` +```js +TOKEN_CONFIG = { + "10000000000000uibcusdc<>10000000000000uibcatom": 10, + "100000000000untrn<>100000000000uibcusdc":{ + "price": "coingecko:neutron-3<>usd-coin", + "ticks": 50 + }, + "1000000000uibcatom<>1000000000untrn":{ + "price": 5, + "amplitude2": 100 + }, + "defaults":{ + "fees": [0,1,2,3,4,5,10,20,50,100,150,200], + "gas": "1000000000untrn" + } +} +``` + # Troubleshooting The chain should be visible at http://localhost:26657 and REST at http://localhost:1317. diff --git a/scripts/helpers.sh b/scripts/helpers.sh index 1e8cc1d..723bcc7 100644 --- a/scripts/helpers.sh +++ b/scripts/helpers.sh @@ -38,30 +38,11 @@ getBotNumber() { fi } -# format for TOKEN_CONFIG is: -# TOKEN_CONFIG = { -# "amountAtokenA<>amountBtokenB": numeric_price_or_PAIR_CONFIG_object, -# "defaults": PAIR_CONFIG -# } -# the object keys are the usable tokens for each pair (to be shared across all bots), -# the object values are the price ratio of tokenB/tokenA, a coingecko pair or a config object: (default values are listed) -# PAIR_CONFIG = { -# "price": 1, # price ratio is of tokenB/tokenA (how many tokenA is required to buy 1 tokenB?), OR -# "price": "coingecko:api_idA<>api_idB", # for live price retrieval, use the coingecko API IDs of the tokens (e.g. "coingecko:cosmos<>neutron-3" for atom<>ntrn pair) -# "ticks": 100, # number of ticks for each bot to deposit -# "fees": [1, 5, 20, 100] # each LP deposit fee may be (randomly) one of the whitelisted fees here -# "gas": "0untrn" # additional gas tokens that bots can use to cover gas fees -# "rebalance_factor": 0.5, # fraction of excessive deposits on either pair side to rebalance on each trade -# "deposit_factor": 0.5, # fraction of the recommended maximum reserves to use on a single tick deposit -# "swap_factor": 0.5, # max fraction of a bot's token reserves to use on a single swap trade (max: 1) -# "swap_accuracy": 100, # ~1% of price: swaps will target within ~1% of current price -# "deposit_accuracy": 1000, # ~10% of price: deposits will target within ~10% of current price -# "amplitude1": 5000, # ~50% of price: current price will vary by ~50% of set price ratio -# "period1": 36000, # ten hours: current price will cycle min->max->min every ten hours -# "amplitude2": 1000, # ~10% of price: current price will vary by an additional ~10% of price ratio -# "period2": 600, # ten minutes: current price will cycle amplitude2 offset every ten minutes -# } -# which is transformed to format for token_config_array = [ +# getTokenConfigArray transforms a given TOKEN_CONFIG (or TOKEN_CONFIG_DEFAULT) object +# into a new format that is easier to query through `jq`. +# the TOKEN_CONFIG and PAIR_CONFIG object format is listed in the README file +# +# token_config_array = [ # { # "pair": [ # { From 40a1fa035f40d053b7e10545739720b181a73e75 Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Thu, 25 Apr 2024 22:55:43 +1000 Subject: [PATCH 07/34] docs: make TOKEN_CONFIG option header larger --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 040b9a9..43aac67 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ All docker-compose env vars are able to be set in both `make start-trade-bot` an eg. `make start-trade-bot BOTS=30 BOT_RAMPING_DELAY=5 TRADE_FREQUENCY_SECONDS=0 TRADE_DURATION_SECONDS=450 MNEMONIC=...` will start a persistent chain that for the first ~10min (7min+ramping) will generate ~5000txs using 30 bots. -#### TOKEN_CONFIG option +### TOKEN_CONFIG option format for TOKEN_CONFIG is: ``` From 414fe0c8104dc72a7a56a700dcbc0a2a0c3010c1 Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Thu, 25 Apr 2024 22:57:51 +1000 Subject: [PATCH 08/34] style: make whitespace more consistent --- README.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 43aac67..939da47 100644 --- a/README.md +++ b/README.md @@ -88,20 +88,20 @@ the object keys are the usable tokens for each pair (to be shared across all bot the object values are the price ratio of tokenB/tokenA, a coingecko pair or a config object: (default values are listed) ``` PAIR_CONFIG = { - "price": 1, # price ratio is of tokenB/tokenA (how many tokenA is required to buy 1 tokenB?), OR - "price": "coingecko:api_idA<>api_idB", # for live price retrieval, use the coingecko API IDs of the tokens (e.g. "coingecko:cosmos<>neutron-3" for atom<>ntrn pair) - "ticks": 100, # number of ticks for each bot to deposit - "fees": [1, 5, 20, 100] # each LP deposit fee may be (randomly) one of the whitelisted fees here - "gas": "0untrn" # additional gas tokens that bots can use to cover gas fees - "rebalance_factor": 0.5, # fraction of excessive deposits on either pair side to rebalance on each trade - "deposit_factor": 0.5, # fraction of the recommended maximum reserves to use on a single tick deposit - "swap_factor": 0.5, # max fraction of a bot's token reserves to use on a single swap trade (max: 1) - "swap_accuracy": 100, # ~1% of price: swaps will target within ~1% of current price - "deposit_accuracy": 1000, # ~10% of price: deposits will target within ~10% of current price - "amplitude1": 5000, # ~50% of price: current price will vary by ~50% of set price ratio - "period1": 36000, # ten hours: current price will cycle min->max->min every ten hours - "amplitude2": 1000, # ~10% of price: current price will vary by an additional ~10% of price ratio - "period2": 600, # ten minutes: current price will cycle amplitude2 offset every ten minutes + "price": 1, # price ratio is of tokenB/tokenA (how many tokenA is required to buy 1 tokenB?), OR + "price": "coingecko:api_idA<>api_idB", # for live price retrieval, use the coingecko API IDs of the tokens (e.g. "coingecko:cosmos<>neutron-3" for atom<>ntrn pair) + "ticks": 100, # number of ticks for each bot to deposit + "fees": [1, 5, 20, 100] # each LP deposit fee may be (randomly) one of the whitelisted fees here + "gas": "0untrn" # additional gas tokens that bots can use to cover gas fees + "rebalance_factor": 0.5, # fraction of excessive deposits on either pair side to rebalance on each trade + "deposit_factor": 0.5, # fraction of the recommended maximum reserves to use on a single tick deposit + "swap_factor": 0.5, # max fraction of a bot's token reserves to use on a single swap trade (max: 1) + "swap_accuracy": 100, # ~1% of price: swaps will target within ~1% of current price + "deposit_accuracy": 1000, # ~10% of price: deposits will target within ~10% of current price + "amplitude1": 5000, # ~50% of price: current price will vary by ~50% of set price ratio + "period1": 36000, # ten hours: current price will cycle min->max->min every ten hours + "amplitude2": 1000, # ~10% of price: current price will vary by an additional ~10% of price ratio + "period2": 600, # ten minutes: current price will cycle amplitude2 offset every ten minutes } ``` From 7625658830652fead6428af9318b794015e07722 Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Mon, 6 May 2024 11:16:18 +1000 Subject: [PATCH 09/34] feat: move most env vars to an .env file --- .env.local.template | 13 +++++++++++++ .env.testnet.template | 15 +++++++++++++++ .gitignore | 3 +++ docker-compose.yml | 17 ++++------------- 4 files changed, 35 insertions(+), 13 deletions(-) create mode 100644 .env.local.template create mode 100644 .env.testnet.template diff --git a/.env.local.template b/.env.local.template new file mode 100644 index 0000000..1387d23 --- /dev/null +++ b/.env.local.template @@ -0,0 +1,13 @@ +# works with local chain from `make build-neutron ...` +CHAIN_ID=test-1 +RPC_ADDRESS=http://0.0.0.0:26657 +API_ADDRESS=http://0.0.0.0:1317 +GAS_PRICES=0.0025untrn +GAS_ADJUSTMENT=2 +TRADE_FREQUENCY_SECONDS=60 +# use a single pair with few ticks to reduce default CPU/memort resources needed +TOKEN_CONFIG={"100000000000uibcusdc<>100000000000untrn":2,"defaults":{"gas":"1000000000untrn","ticks":50,"amplitude2":100}} +# this mnemonic is defined in the default local setup: https://github.com/neutron-org/neutron/blob/v3.0.0/network/init.sh#L19-L21 +FAUCET_MNEMONIC=veteran try aware erosion drink dance decade comic dawn museum release episode original list ability owner size tuition surface ceiling depth seminar capable only +# test the pool withdrawal mechanism to return tokens to the faucet with: +ON_EXIT_WITHDRAW_POOLS=1 diff --git a/.env.testnet.template b/.env.testnet.template new file mode 100644 index 0000000..b7d7618 --- /dev/null +++ b/.env.testnet.template @@ -0,0 +1,15 @@ +# works with testnet, for current information check https://github.com/cosmos/chain-registry/blob/master/neutron/chain.json +CHAIN_ID=pion-1 +RPC_ADDRESS=https://rpc-lb-pion.ntrn.tech:443 +API_ADDRESS=https://rest-lb-pion.ntrn.tech:443 +GAS_PRICES=0.025untrn +GAS_ADJUSTMENT=2 +# it is helpful to see multiple swaps per minute for more realistic minute candles of a price timeseries chart +TRADE_FREQUENCY_SECONDS=20 +# use demo pair amount from demo faucet and untrn amount from pion-1 faucet +TOKEN_CONFIG={"10000000factory/neutron19glux3jzdfyyz6ylmuksgxfj5phdaxfr2uhy86/factoryATOM<>10000000factory/neutron19glux3jzdfyyz6ylmuksgxfj5phdaxfr2uhy86/factoryNTRN":{"price":"coingecko:usd-coin<>neutron-3","ticks":80,"deposit_accuracy":100,"swap_accuracy":5,"gas":"2000000untrn"}} +# running a single docker image requires a DOCKER_ENV to replicate a docker-compose environment +DOCKER_ENV={"Config":{"Hostname":"trading-bot","Labels":{"com.docker.compose.container-number":1}}} +# add credentials of accounts +COINGECKO_API_TOKEN= +MNEMONIC= diff --git a/.gitignore b/.gitignore index 9665ba9..deef8ee 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,9 @@ keystore.db contracts/artifacts/ contracts/*.wasm +# env +.env + # IDEs *.iml .idea diff --git a/docker-compose.yml b/docker-compose.yml index 7843cec..ec71d3d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -51,24 +51,16 @@ services: command: ["/bin/bash", "./scripts/run_trade_bot.sh"] deploy: replicas: ${BOTS:-1} + env_file: + - ${ENV_FILE:-.env} environment: - BOT_RAMPING_DELAY=${BOT_RAMPING_DELAY:-3} # seconds between starting each bot + # override env file with variables that connect to the neutron-node service here - CHAIN_ID=${CHAIN_ID:-test-1} - RPC_ADDRESS=${RPC_ADDRESS:-http://neutron-node:26657} - API_ADDRESS=${API_ADDRESS:-http://neutron-node:1317} + # this var is set when using `make test-trade-bot` - TRADE_DURATION_SECONDS=${TRADE_DURATION_SECONDS:-} - - TRADE_FREQUENCY_SECONDS=${TRADE_FREQUENCY_SECONDS:-60} - - ON_EXIT_WITHDRAW_POOLS=${ON_EXIT_WITHDRAW_POOLS:-} - - GAS_ADJUSTMENT=${GAS_ADJUSTMENT:-2} - - GAS_PRICES=${GAS_PRICES:-0.0025untrn} - # optional faucet mnemonic should be set with specific FAUCET_MNEMONIC: - - FAUCET_MNEMONIC=${FAUCET_MNEMONIC} - # optional bot mnemonics can be set using BOT_MNEMONIC/S or MNEMONIC/S: - # mnemonics may be delimited with: line breaks, tabs, semicolons, commas, and multiple spaces - - MNEMONICS=${MNEMONICS:-$MNEMONIC} - - BOT_MNEMONICS=${BOT_MNEMONICS:-$BOT_MNEMONIC} - # allow passing through a TOKEN_CONFIG object, defaulting to TOKEN_CONFIG_DEFAULT if not found - - TOKEN_CONFIG=${TOKEN_CONFIG} # use (from default local node test wallets) up to about 10,000,000 (display) tokens in each pool # use range of token amounts to visualize multiple orders of magnitude in dev UI - TOKEN_CONFIG_DEFAULT= @@ -87,7 +79,6 @@ services: "gas":"1000000000untrn" } } - - COINGECKO_API_TOKEN=${COINGECKO_API_TOKEN} volumes: - /var/run/docker.sock:/var/run/docker.sock networks: From ecd55bd6236df90f5c5c877dbdfd985592a947bf Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Mon, 6 May 2024 11:34:51 +1000 Subject: [PATCH 10/34] feat: move TOKEN_CONFIG_DEFAULT to local TOKEN_CONFIG example --- .env.local.template | 17 +++++++++++++++-- docker-compose.yml | 18 ------------------ scripts/helpers.sh | 2 +- 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/.env.local.template b/.env.local.template index 1387d23..fcacf92 100644 --- a/.env.local.template +++ b/.env.local.template @@ -5,8 +5,21 @@ API_ADDRESS=http://0.0.0.0:1317 GAS_PRICES=0.0025untrn GAS_ADJUSTMENT=2 TRADE_FREQUENCY_SECONDS=60 -# use a single pair with few ticks to reduce default CPU/memort resources needed -TOKEN_CONFIG={"100000000000uibcusdc<>100000000000untrn":2,"defaults":{"gas":"1000000000untrn","ticks":50,"amplitude2":100}} +# this token config demonstrates several ways to define price and other vars +# use range of token amounts to visualize multiple orders of magnitude in dev UI +TOKEN_CONFIG=' + { + "10000000000000uibcusdc<>10000000000000uibcatom": 10, + "100000000000uibcusdc<>100000000000untrn": { + "price": 2, + "ticks": 50 + }, + "defaults": { + "fees": [0,1,2,3,4,5,10,20,50,100,150,200], + "gas": "1000000000untrn" + } + } +' # this mnemonic is defined in the default local setup: https://github.com/neutron-org/neutron/blob/v3.0.0/network/init.sh#L19-L21 FAUCET_MNEMONIC=veteran try aware erosion drink dance decade comic dawn museum release episode original list ability owner size tuition surface ceiling depth seminar capable only # test the pool withdrawal mechanism to return tokens to the faucet with: diff --git a/docker-compose.yml b/docker-compose.yml index ec71d3d..aec3c7c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -61,24 +61,6 @@ services: - API_ADDRESS=${API_ADDRESS:-http://neutron-node:1317} # this var is set when using `make test-trade-bot` - TRADE_DURATION_SECONDS=${TRADE_DURATION_SECONDS:-} - # use (from default local node test wallets) up to about 10,000,000 (display) tokens in each pool - # use range of token amounts to visualize multiple orders of magnitude in dev UI - - TOKEN_CONFIG_DEFAULT= - { - "10000000000000uibcusdc<>10000000000000uibcatom":10, - "100000000000uibcusdc<>100000000000untrn":{ - "price":2, - "ticks":50 - }, - "1000000000uibcatom<>1000000000untrn":{ - "price":0.2, - "ticks":30 - }, - "defaults":{ - "fees":[0,1,2,3,4,5,10,20,50,100,150,200], - "gas":"1000000000untrn" - } - } volumes: - /var/run/docker.sock:/var/run/docker.sock networks: diff --git a/scripts/helpers.sh b/scripts/helpers.sh index 723bcc7..8c0245b 100644 --- a/scripts/helpers.sh +++ b/scripts/helpers.sh @@ -69,7 +69,7 @@ getTokenConfigArray() { # this includes extra gas passed in the config or default config object bot_count=$( getBotCount ) # by default shift the period of each token pair slightly so they are not exactly in sync - echo "${TOKEN_CONFIG:-"$TOKEN_CONFIG_DEFAULT"}" | jq -r ' + echo "${TOKEN_CONFIG:-"{}"}" | jq -r ' .defaults as $defaults | del(.defaults) | to_entries From e0390c77e40eafdecfac0fa9d3a4d15c6e6d4b18 Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Mon, 6 May 2024 11:36:01 +1000 Subject: [PATCH 11/34] docs: note default TRADE_FREQUENCY_SECONDS value --- scripts/run_trade_bot.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/run_trade_bot.sh b/scripts/run_trade_bot.sh index 2e85efb..caa194b 100644 --- a/scripts/run_trade_bot.sh +++ b/scripts/run_trade_bot.sh @@ -98,6 +98,7 @@ two_pi=$( echo "scale=8; 8*a(1)" | bc -l ) start_epoch=$( bash $SCRIPTPATH/helpers.sh getBotStartTime ) sleep $(( $start_epoch - $EPOCHSECONDS > 0 ? $start_epoch - $EPOCHSECONDS : 0 )) +# enforce a default TRADE_FREQUENCY_SECONDS or the script will fail TRADE_FREQUENCY_SECONDS="${TRADE_FREQUENCY_SECONDS:-60}" # add function to check when the script should finish From 1b33b8df1ea24e3f07d939952d470f9ce7b65ca3 Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Mon, 6 May 2024 11:36:45 +1000 Subject: [PATCH 12/34] feat: set default BOT_RAMPING_DELAY outside of docker compose env --- docker-compose.yml | 1 - scripts/helpers.sh | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index aec3c7c..b12e74f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -54,7 +54,6 @@ services: env_file: - ${ENV_FILE:-.env} environment: - - BOT_RAMPING_DELAY=${BOT_RAMPING_DELAY:-3} # seconds between starting each bot # override env file with variables that connect to the neutron-node service here - CHAIN_ID=${CHAIN_ID:-test-1} - RPC_ADDRESS=${RPC_ADDRESS:-http://neutron-node:26657} diff --git a/scripts/helpers.sh b/scripts/helpers.sh index 8c0245b..b52e2be 100644 --- a/scripts/helpers.sh +++ b/scripts/helpers.sh @@ -192,7 +192,7 @@ getBotStartTime() { fi done echo "waited. found first start time: $first_bot_start_time" > /dev/stderr - echo "$(( ($bot_number - 1) * $BOT_RAMPING_DELAY + $first_bot_start_time ))" + echo "$(( ($bot_number - 1) * "${BOT_RAMPING_DELAY:-0}" + $first_bot_start_time ))" fi } getBotEndTime() { From a80ebb4903e78ca606db9eb9d65d1474b322e8c8 Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Mon, 6 May 2024 11:47:21 +1000 Subject: [PATCH 13/34] feat: make DOCKER_ENV var optional when run outside of docker-compose --- .env.testnet.template | 2 -- scripts/helpers.sh | 8 +++++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.env.testnet.template b/.env.testnet.template index b7d7618..90b1f70 100644 --- a/.env.testnet.template +++ b/.env.testnet.template @@ -8,8 +8,6 @@ GAS_ADJUSTMENT=2 TRADE_FREQUENCY_SECONDS=20 # use demo pair amount from demo faucet and untrn amount from pion-1 faucet TOKEN_CONFIG={"10000000factory/neutron19glux3jzdfyyz6ylmuksgxfj5phdaxfr2uhy86/factoryATOM<>10000000factory/neutron19glux3jzdfyyz6ylmuksgxfj5phdaxfr2uhy86/factoryNTRN":{"price":"coingecko:usd-coin<>neutron-3","ticks":80,"deposit_accuracy":100,"swap_accuracy":5,"gas":"2000000untrn"}} -# running a single docker image requires a DOCKER_ENV to replicate a docker-compose environment -DOCKER_ENV={"Config":{"Hostname":"trading-bot","Labels":{"com.docker.compose.container-number":1}}} # add credentials of accounts COINGECKO_API_TOKEN= MNEMONIC= diff --git a/scripts/helpers.sh b/scripts/helpers.sh index b52e2be..22b7c21 100644 --- a/scripts/helpers.sh +++ b/scripts/helpers.sh @@ -5,11 +5,13 @@ set -e # so you can optionally add a Docker "env" JSON string to run a single bot without Docker getDockerEnv() { # get this Docker container env info - if [ ! -z "$DOCKER_ENV" ] + if [ ! -z "$HOSTNAME" ] then - echo "$DOCKER_ENV" - else curl -s --unix-socket /run/docker.sock http://docker/containers/$HOSTNAME/json + else + # default will return a setup that works when running image as a single Docker container + # eg. `docker run -it --rm --env-file .env dex-trading-bot:latest` + echo "$DOCKER_ENV:-'{"Config":{"Hostname":"trading-bot","Labels":{"com.docker.compose.container-number":1}}}}'" fi } getDockerEnvs() { From 40a19c952541ecca8f7c892a5701c0831db01091 Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Mon, 6 May 2024 11:38:44 +1000 Subject: [PATCH 14/34] feat: add SKIP_DEPOSIT option --- .env.testnet.template | 5 +++++ scripts/run_trade_bot.sh | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.env.testnet.template b/.env.testnet.template index 90b1f70..06c37e8 100644 --- a/.env.testnet.template +++ b/.env.testnet.template @@ -11,3 +11,8 @@ TOKEN_CONFIG={"10000000factory/neutron19glux3jzdfyyz6ylmuksgxfj5phdaxfr2uhy86/fa # add credentials of accounts COINGECKO_API_TOKEN= MNEMONIC= + +# note: consider using SKIP_INITIAL_DEPOSIT=1 when starting / restarting a testnet bot +# a testnet bot may need to be restarted often and we don't want to repeat +# the initial deposit. the initial deposit can be made and adjusted at +# any time through the UI at https://app.testnet.duality.xyz/ diff --git a/scripts/run_trade_bot.sh b/scripts/run_trade_bot.sh index caa194b..8fa1379 100644 --- a/scripts/run_trade_bot.sh +++ b/scripts/run_trade_bot.sh @@ -246,7 +246,7 @@ do echo "pair: $tokenA<>$tokenB current price index is $current_price ($( echo "1.0001^$current_price" | bc -l ) $tokenA per $tokenB)" # if initial ticks do not yet exist, add them so we have some liquidity to swap with - if [ -z "${tokens_available["$pair_index-$tokenA"]}" ] + if [ -z "$SKIP_INITIAL_DEPOSIT" ] && [ -z "${tokens_available["$pair_index-$tokenA"]}" ] then echo "making deposit: initial ticks for $tokenA and $tokenB" # apply half of the available tokens to all tick indexes specified From 89e1cea73d6e1b43080510230c75064f61c93d47 Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Wed, 3 Jul 2024 17:27:14 +1000 Subject: [PATCH 15/34] fix: ensure to fetch up to date tags of the Neutron git repo --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index af437da..409f688 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ init-neutron: ifeq (,$(wildcard $(REPOS_DIR)/neutron)) cd $(REPOS_DIR) && git clone -b $(NEUTRON_VERSION) https://github.com/neutron-org/neutron.git else - cd $(REPOS_DIR)/neutron && git fetch origin $(NEUTRON_VERSION) && git checkout $(NEUTRON_VERSION) + cd $(REPOS_DIR)/neutron && git fetch origin $(NEUTRON_VERSION) && git fetch origin $(NEUTRON_VERSION) --tags && git checkout $(NEUTRON_VERSION) endif init-hermes: From ffabb034da82833036ddb2569fbe1bdaf9f231e5 Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Wed, 3 Jul 2024 17:28:12 +1000 Subject: [PATCH 16/34] fix: new (SDK50) setup doesn't support setting GRPCWEB address --- docker-compose.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index b12e74f..fd47a10 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -22,8 +22,7 @@ services: --log_level "$$LOG_LEVEL" \ --home "$$CHAIN_DIR" \ --pruning=nothing \ - --grpc.address="0.0.0.0:$$GRPCPORT" \ - --grpc-web.address="0.0.0.0:$$GRPCWEB" + --grpc.address="0.0.0.0:$$GRPCPORT" ' container_name: neutron-node volumes: From 1c7b983f0f9912fe1fa8c033a3748c2cad8634b0 Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Wed, 3 Jul 2024 17:29:18 +1000 Subject: [PATCH 17/34] fix: ensure local DOCKER_ENV can still be read if HOSTNAME is set --- scripts/helpers.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/helpers.sh b/scripts/helpers.sh index 22b7c21..0e3fbfc 100644 --- a/scripts/helpers.sh +++ b/scripts/helpers.sh @@ -5,13 +5,13 @@ set -e # so you can optionally add a Docker "env" JSON string to run a single bot without Docker getDockerEnv() { # get this Docker container env info - if [ ! -z "$HOSTNAME" ] + if [ ! -z "$HOSTNAME" ] && [ -z "$DOCKER_ENV" ] then curl -s --unix-socket /run/docker.sock http://docker/containers/$HOSTNAME/json else # default will return a setup that works when running image as a single Docker container # eg. `docker run -it --rm --env-file .env dex-trading-bot:latest` - echo "$DOCKER_ENV:-'{"Config":{"Hostname":"trading-bot","Labels":{"com.docker.compose.container-number":1}}}}'" + echo "${DOCKER_ENV:-'{"Config":{"Hostname":"trading-bot","Labels":{"com.docker.compose.container-number":1}}}}'}" fi } getDockerEnvs() { From 3a341a5c2f7b5404ad57780e0cf76f5fcda45040 Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Wed, 3 Jul 2024 18:52:22 +1000 Subject: [PATCH 18/34] feat: allow tokens of different decimal exponent to have correct price --- README.md | 2 ++ scripts/helpers.sh | 1 + scripts/run_trade_bot.sh | 20 +++++++++++--------- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 939da47..195778f 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ the object values are the price ratio of tokenB/tokenA, a coingecko pair or a co PAIR_CONFIG = { "price": 1, # price ratio is of tokenB/tokenA (how many tokenA is required to buy 1 tokenB?), OR "price": "coingecko:api_idA<>api_idB", # for live price retrieval, use the coingecko API IDs of the tokens (e.g. "coingecko:cosmos<>neutron-3" for atom<>ntrn pair) + "price_decimals": [0, 0] # the display token decimals (exponents) over base token amounts (eg. for ETH=10^18wei, USDC=10^6uUSDC use [18, 6]) "ticks": 100, # number of ticks for each bot to deposit "fees": [1, 5, 20, 100] # each LP deposit fee may be (randomly) one of the whitelisted fees here "gas": "0untrn" # additional gas tokens that bots can use to cover gas fees @@ -115,6 +116,7 @@ TOKEN_CONFIG = { "10000000000000uibcusdc<>10000000000000uibcatom": 10, "100000000000untrn<>100000000000uibcusdc":{ "price": "coingecko:neutron-3<>usd-coin", + "price_decimals": [6, 6], # not required here (no decimal difference) "ticks": 50 }, "1000000000uibcatom<>1000000000untrn":{ diff --git a/scripts/helpers.sh b/scripts/helpers.sh index 0e3fbfc..d9ba628 100644 --- a/scripts/helpers.sh +++ b/scripts/helpers.sh @@ -92,6 +92,7 @@ getTokenConfigArray() { pair: .value.pair, config: { price: (.value.price // $defaults.price // 1), + price_decimals: (.value.price_decimals // $defaults.price_decimals // [0, 0]), ticks: (.value.ticks // $defaults.ticks // 100), fees: (.value.fees // $defaults.fees // [1, 5, 20, 100]), rebalance_factor: (.value.rebalance_factor // $defaults.rebalance_factor // 0.5), diff --git a/scripts/run_trade_bot.sh b/scripts/run_trade_bot.sh index 8fa1379..a42c8c0 100644 --- a/scripts/run_trade_bot.sh +++ b/scripts/run_trade_bot.sh @@ -150,6 +150,7 @@ do deposit_index_accuracy=$( echo "$token_pair_config" | jq -r '.deposit_accuracy' ) swap_index_accuracy=$( echo "$token_pair_config" | jq -r '.swap_accuracy' ) price_config=$( echo "$token_pair_config" | jq -r '.price' ) + price_decimals_diff=$( echo "$token_pair_config" | jq -r '.price_decimals[0] - .price_decimals[1]' ) # if price is a number, i.e. if price is set manually if (( $(echo "$price_config" | grep -c '^[0-9]\+\(\.[0-9]\+\)\?$') == 1 )) @@ -163,15 +164,15 @@ do period2=$( echo "$token_pair_config" | jq -r '.period2' ) # convert price to price index here + pair_display_price=$( echo "$token_pair_config" | jq -r '.price' ) price_index=$( echo "$token_pair_config" | jq -r '((.price | log)/(1.0001 | log) | round)' ) echo "calculated price index before approximation $price_index" # determine the new current price goal # approximate price with sine curves of given amplitude and period # by default: macro curve (1) oscillates over hours / micro curve (2) oscillates over minutes - current_price=$( - rounded_calculation \ - "$price_index + $amplitude1*s($EPOCHSECONDS / $period1 * $two_pi) + $amplitude2*s($EPOCHSECONDS / $period2 * $two_pi)" + pair_price_index_adjustment=$( + bc -l " $amplitude1*s($EPOCHSECONDS / $period1 * $two_pi) + $amplitude2*s($EPOCHSECONDS / $period2 * $two_pi) " ) # if price is configured to be fetched from coingecko @@ -212,18 +213,19 @@ do echo "got prices: $tokenA = $priceA, $tokenB = $priceB" - # convert assets price ratio to price index here - current_price=$( - rounded_calculation \ - "l($priceB/$priceA) / l(1.0001)" - ) - echo "calculated price index $current_price" + pair_display_price=$( bc -l " $priceB/$priceA " ) else echo "error: unexpected $tokenA<>$tokenB price format $price_config: expected a number or a coingecko pair" exit 1 fi + # calculate current price index from display price + display price exponent adjustment + oscillation adjustment: + current_price=$( + rounded_calculation \ + "l($pair_display_price) / l(1.0001) + $price_decimals_diff * l(10) / l(1.0001) + ${pair_price_index_adjustment:-"0"}" + ) + # calculate token amounts we will use in the initial deposit # the amount deposited by all bots should not be more than can be swapped by any one bot # eg. config 300A<>300B with 2 bots: From 484f6d581d1f34685d800a48d280f51fd802ae76 Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Wed, 3 Jul 2024 18:53:03 +1000 Subject: [PATCH 19/34] fix: spelling --- scripts/run_trade_bot.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/run_trade_bot.sh b/scripts/run_trade_bot.sh index a42c8c0..e22052e 100644 --- a/scripts/run_trade_bot.sh +++ b/scripts/run_trade_bot.sh @@ -294,7 +294,7 @@ do # add some randomness into price goal (within swap_index_accuracy) deviation=$(( $RANDOM % ( $swap_index_accuracy * 2 ) - $swap_index_accuracy )) - # compute goal price (and inverse gola price for inverted token pair order: tokenB<>tokenA) + # compute goal price (and inverse goal price for inverted token pair order: tokenB<>tokenA) goal_price=$(( $current_price + $deviation )) goal_price_ratio=$( echo "1.0001^$goal_price" | bc -l ) From cfaeeca93abbad1596f4aa7a66f072e3266720b6 Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Wed, 3 Jul 2024 19:09:25 +1000 Subject: [PATCH 20/34] docs: add more detail to placed trade logs --- scripts/run_trade_bot.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/run_trade_bot.sh b/scripts/run_trade_bot.sh index e22052e..040bb4e 100644 --- a/scripts/run_trade_bot.sh +++ b/scripts/run_trade_bot.sh @@ -312,8 +312,8 @@ do echo "check: place-limit-order: tokenA side: is $first_tickA_price_ratio > $goal_price_ratio ?" if [ "$first_tickA_price_ratio" != "null" ] && (( $( bc <<< "$first_tickA_price_ratio > $goal_price_ratio" ) )) then - echo "making place-limit-order: '$tokenB' -> '$tokenA'" trade_amount="$( neutrond query bank balances $address --denom $tokenB --output json | jq -r "(.amount | tonumber) * $swap_factor | floor" )" + echo "making place-limit-order: '$tokenB' -> '$tokenA' to goal price $goal_price with $trade_amount tokens" if [ "$trade_amount" -gt "0" ] then tx_response="$( @@ -350,8 +350,8 @@ do echo "check: place-limit-order: tokenB side: is $first_tickB_price_ratio < $goal_price_ratio ?" if [ "$first_tickB_price_ratio" != "null" ] && (( $(bc <<< "$first_tickB_price_ratio < $goal_price_ratio") )) then - echo "making place-limit-order: '$tokenA' -> '$tokenB'" trade_amount="$( neutrond query bank balances $address --denom $tokenA --output json | jq -r "(.amount | tonumber) * $swap_factor | floor" )" + echo "making place-limit-order: '$tokenA' -> '$tokenB' to goal price $goal_price with $trade_amount tokens" if [ "$trade_amount" -gt "0" ] then tx_response="$( From 2f88553ee4867578fb0555137b01c0859da960e1 Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Wed, 3 Jul 2024 21:53:16 +1000 Subject: [PATCH 21/34] fix: allow trade amount to be increased to required minimum amount --- scripts/run_trade_bot.sh | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/scripts/run_trade_bot.sh b/scripts/run_trade_bot.sh index 040bb4e..6526049 100644 --- a/scripts/run_trade_bot.sh +++ b/scripts/run_trade_bot.sh @@ -312,10 +312,18 @@ do echo "check: place-limit-order: tokenA side: is $first_tickA_price_ratio > $goal_price_ratio ?" if [ "$first_tickA_price_ratio" != "null" ] && (( $( bc <<< "$first_tickA_price_ratio > $goal_price_ratio" ) )) then - trade_amount="$( neutrond query bank balances $address --denom $tokenB --output json | jq -r "(.amount | tonumber) * $swap_factor | floor" )" + balance_amount="$( neutrond query bank balances $address --denom $tokenB --output json | jq -r ".amount" )" + trade_amount="$( echo "$balance_amount" | jq -r "(. | tonumber) * $swap_factor | floor" )" echo "making place-limit-order: '$tokenB' -> '$tokenA' to goal price $goal_price with $trade_amount tokens" - if [ "$trade_amount" -gt "0" ] + directional_goal_price="$(( $goal_price * -1 ))" + minimum_trade_amount="$( rounded_calculation "1.0001^$directional_goal_price + 1" )" + if [ "$balance_amount" -gt "$minimum_trade_amount" ] then + if [ "$minimum_trade_amount" -gt "$trade_amount" ] + then + trade_amount="$minimum_trade_amount" + echo "changing place-limit-order: increase amount to mininum: $minimum_trade_amount" + fi tx_response="$( neutrond tx dex place-limit-order \ `# receiver` \ @@ -325,7 +333,7 @@ do `# token out` \ $tokenA \ `# tickIndexInToOut (note: this is the limit that we will swap up to, the goal)` \ - "[$(( $goal_price * -1 ))]" \ + "[$directional_goal_price]" \ `# amount in: allow up to a good fraction of the denom balance to be traded, to try to reach the tick limit` \ "$trade_amount" \ `# order type enum see: https://github.com/duality-labs/duality/blob/v0.2.1/proto/duality/dex/tx.proto#L81-L87` \ @@ -336,7 +344,7 @@ do )" tx_result="$( bash $SCRIPTPATH/helpers.sh waitForTxResult "$tx_response" "swapped: ticks toward target tick index of $goal_price" )" else - echo "skipping place-limit-order: '$tokenB' -> '$tokenA': not enough funds" + echo "skipping place-limit-order: '$tokenB' -> '$tokenA': not enough funds for trade (balance: $balance_amount, required: $minimum_trade_amount)" fi else echo "ignore place-limit-order: '$tokenB' -> '$tokenA': no liquidity to arbitrage" @@ -350,10 +358,18 @@ do echo "check: place-limit-order: tokenB side: is $first_tickB_price_ratio < $goal_price_ratio ?" if [ "$first_tickB_price_ratio" != "null" ] && (( $(bc <<< "$first_tickB_price_ratio < $goal_price_ratio") )) then - trade_amount="$( neutrond query bank balances $address --denom $tokenA --output json | jq -r "(.amount | tonumber) * $swap_factor | floor" )" + balance_amount="$( neutrond query bank balances $address --denom $tokenA --output json | jq -r ".amount" )" + trade_amount="$( echo "$balance_amount" | jq -r "(. | tonumber) * $swap_factor | floor" )" echo "making place-limit-order: '$tokenA' -> '$tokenB' to goal price $goal_price with $trade_amount tokens" - if [ "$trade_amount" -gt "0" ] + directional_goal_price="$goal_price" + minimum_trade_amount="$( rounded_calculation "1.0001^$directional_goal_price + 1" )" + if [ "$balance_amount" -gt "$minimum_trade_amount" ] then + if [ "$minimum_trade_amount" -gt "$trade_amount" ] + then + trade_amount="$minimum_trade_amount" + echo "changing place-limit-order: increase amount to mininum: $minimum_trade_amount" + fi tx_response="$( neutrond tx dex place-limit-order \ `# receiver` \ @@ -363,7 +379,7 @@ do `# token out` \ $tokenB \ `# tickIndexInToOut (note: this is the limit that we will swap up to, the goal)` \ - "[$goal_price]" \ + "[$directional_goal_price]" \ `# amount in: allow up to a good fraction of the denom balance to be traded, to try to reach the tick limit` \ "$trade_amount" \ `# order type enum see: https://github.com/duality-labs/duality/blob/v0.2.1/proto/duality/dex/tx.proto#L81-L87` \ @@ -374,7 +390,7 @@ do )" tx_result="$( bash $SCRIPTPATH/helpers.sh waitForTxResult "$tx_response" "swapped: ticks toward target tick index of $goal_price" )" else - echo "skipping place-limit-order: '$tokenA' -> '$tokenB': not enough funds" + echo "skipping place-limit-order: '$tokenA' -> '$tokenB': not enough funds for trade (balance: $balance_amount, required: $minimum_trade_amount)" fi else echo "ignore place-limit-order: '$tokenA' -> '$tokenB': no liquidity to arbitrage" From c16963e4ca3eb4fa6508062ebd640cd83e989a23 Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Wed, 3 Jul 2024 22:24:12 +1000 Subject: [PATCH 22/34] fix: bc needs a herestring to read a string --- scripts/run_trade_bot.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/run_trade_bot.sh b/scripts/run_trade_bot.sh index 6526049..f77b542 100644 --- a/scripts/run_trade_bot.sh +++ b/scripts/run_trade_bot.sh @@ -172,7 +172,7 @@ do # approximate price with sine curves of given amplitude and period # by default: macro curve (1) oscillates over hours / micro curve (2) oscillates over minutes pair_price_index_adjustment=$( - bc -l " $amplitude1*s($EPOCHSECONDS / $period1 * $two_pi) + $amplitude2*s($EPOCHSECONDS / $period2 * $two_pi) " + bc -l <<< " $amplitude1*s($EPOCHSECONDS / $period1 * $two_pi) + $amplitude2*s($EPOCHSECONDS / $period2 * $two_pi) " ) # if price is configured to be fetched from coingecko @@ -213,7 +213,7 @@ do echo "got prices: $tokenA = $priceA, $tokenB = $priceB" - pair_display_price=$( bc -l " $priceB/$priceA " ) + pair_display_price=$( bc -l <<< " $priceB/$priceA " ) else echo "error: unexpected $tokenA<>$tokenB price format $price_config: expected a number or a coingecko pair" From 3d1631b7ea10a4d747a3cd718c622a8fc2d97ef7 Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Wed, 3 Jul 2024 22:27:03 +1000 Subject: [PATCH 23/34] fix: spaces --- scripts/helpers.sh | 2 +- scripts/run_trade_bot.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/helpers.sh b/scripts/helpers.sh index d9ba628..2f8ef8b 100644 --- a/scripts/helpers.sh +++ b/scripts/helpers.sh @@ -92,7 +92,7 @@ getTokenConfigArray() { pair: .value.pair, config: { price: (.value.price // $defaults.price // 1), - price_decimals: (.value.price_decimals // $defaults.price_decimals // [0, 0]), + price_decimals: (.value.price_decimals // $defaults.price_decimals // [0, 0]), ticks: (.value.ticks // $defaults.ticks // 100), fees: (.value.fees // $defaults.fees // [1, 5, 20, 100]), rebalance_factor: (.value.rebalance_factor // $defaults.rebalance_factor // 0.5), diff --git a/scripts/run_trade_bot.sh b/scripts/run_trade_bot.sh index f77b542..1f74fcb 100644 --- a/scripts/run_trade_bot.sh +++ b/scripts/run_trade_bot.sh @@ -356,7 +356,7 @@ do | jq -r ".tick_liquidity[0].pool_reserves.price_opposite_taker_to_maker" ) echo "check: place-limit-order: tokenB side: is $first_tickB_price_ratio < $goal_price_ratio ?" - if [ "$first_tickB_price_ratio" != "null" ] && (( $(bc <<< "$first_tickB_price_ratio < $goal_price_ratio") )) + if [ "$first_tickB_price_ratio" != "null" ] && (( $( bc <<< "$first_tickB_price_ratio < $goal_price_ratio" ) )) then balance_amount="$( neutrond query bank balances $address --denom $tokenA --output json | jq -r ".amount" )" trade_amount="$( echo "$balance_amount" | jq -r "(. | tonumber) * $swap_factor | floor" )" From 93d20030cd090b3e0f314d3c898f66699908ab90 Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Wed, 3 Jul 2024 23:05:36 +1000 Subject: [PATCH 24/34] fix: price direction to be consistent with pair_display_price direction --- scripts/run_trade_bot.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/run_trade_bot.sh b/scripts/run_trade_bot.sh index 1f74fcb..732ba29 100644 --- a/scripts/run_trade_bot.sh +++ b/scripts/run_trade_bot.sh @@ -150,7 +150,7 @@ do deposit_index_accuracy=$( echo "$token_pair_config" | jq -r '.deposit_accuracy' ) swap_index_accuracy=$( echo "$token_pair_config" | jq -r '.swap_accuracy' ) price_config=$( echo "$token_pair_config" | jq -r '.price' ) - price_decimals_diff=$( echo "$token_pair_config" | jq -r '.price_decimals[0] - .price_decimals[1]' ) + price_decimals_diff=$( echo "$token_pair_config" | jq -r '.price_decimals[1] - .price_decimals[0]' ) # if price is a number, i.e. if price is set manually if (( $(echo "$price_config" | grep -c '^[0-9]\+\(\.[0-9]\+\)\?$') == 1 )) From eaa8df76319c11bb918fc9ac5be6569a8ff45244 Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Fri, 18 Oct 2024 09:59:40 +1000 Subject: [PATCH 25/34] feat: tag neutron-node with current version --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 409f688..50649bb 100644 --- a/Makefile +++ b/Makefile @@ -52,6 +52,7 @@ build-gaia: init-dir init-gaia build-neutron: init-dir init-neutron cd $(REPOS_DIR)/neutron && $(MAKE) build-docker-image + docker tag neutron-node:latest neutron-node:$(NEUTRON_VERSION) build-hermes: init-dir init-hermes cd $(SETUP_DIR) && $(MAKE) build-hermes From 0e7a35dd204dacdbcae3ed5a2e8a6ad329bc62d1 Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Fri, 18 Oct 2024 10:01:24 +1000 Subject: [PATCH 26/34] fix: allow Docker compose service to be built without heighliner image --- Dockerfile | 20 ++++++++++++-------- Makefile | 9 +++++++-- docker-compose.yml | 7 ++++++- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/Dockerfile b/Dockerfile index b62339c..6ba82b0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,18 @@ -# Use neutron binary version given through version number or heighliner image -# eg. passing a locally made heighliner image as NEUTRON_IMAGE -ARG NEUTRON_VERSION -# Use Heighliner build by default to get around building for correct platform issue -# as Heighliner build support multiple platforms. More details in commit message -ARG NEUTRON_IMAGE=ghcr.io/strangelove-ventures/heighliner/neutron:${NEUTRON_VERSION} +ARG NEUTRON_VERSION=latest -FROM "$NEUTRON_IMAGE" as neutrond-binary +# the neutron binary image is typically built on amd64 (but may be changed) +# see: https://github.com/neutron-org/neutron/blob/v5.0.0-rc0/Makefile#L107-L122 +ARG BUILDPLATFORM=amd64 + +# optionally specify a difference image to get the binary from +ARG NEUTRON_IMAGE=neutron-${BUILDPLATFORM}:${NEUTRON_VERSION} + +# make build platform consistent across images to avoid docker.io lookup error +# see: https://stackoverflow.com/questions/20481225/how-can-i-use-a-local-image-as-the-base-image-with-a-dockerfile#69798220 +FROM --platform=${BUILDPLATFORM} ${NEUTRON_IMAGE} AS neutrond-binary # allow this container to contact other Docker containers through the docker CLI -FROM docker:24.0.5-cli +FROM --platform=${BUILDPLATFORM} docker:24.0.5-cli # add additional dependencies for the testnet scripts RUN apk add bash curl grep jq; diff --git a/Makefile b/Makefile index 50649bb..7ce1cb1 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ REPOS_DIR ?= ./repos SETUP_DIR ?= $(REPOS_DIR)/neutron-integration-tests/setup +DOCKER ?= docker COMPOSE ?= docker-compose NEUTRON_VERSION ?= v2.0.2 GAIA_VERSION ?= v14.1.0 @@ -54,6 +55,10 @@ build-neutron: init-dir init-neutron cd $(REPOS_DIR)/neutron && $(MAKE) build-docker-image docker tag neutron-node:latest neutron-node:$(NEUTRON_VERSION) +build-neutron-static-linux-amd64: init-dir init-neutron + cd $(REPOS_DIR)/neutron && $(MAKE) build-static-linux-amd64 + docker tag neutron-amd64:latest neutron-amd64:$(NEUTRON_VERSION) + build-hermes: init-dir init-hermes cd $(SETUP_DIR) && $(MAKE) build-hermes @@ -84,8 +89,8 @@ clean: # --- new docker compose network commands --- -build-trade-bot: - @$(COMPOSE) build --build-arg NEUTRON_VERSION=$(NEUTRON_VERSION) +build-trade-bot: build-neutron-static-linux-amd64 + @$(DOCKER) build . -t dex-trading-bot:$(NEUTRON_VERSION) --build-arg NEUTRON_VERSION=$(NEUTRON_VERSION) start-trade-bot: build-trade-bot @$(COMPOSE) up diff --git a/docker-compose.yml b/docker-compose.yml index fd47a10..d7c7b38 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: '3.8' services: neutron-node: - image: neutron-node + image: neutron-node:${NEUTRON_VERSION:-latest} command: > /bin/bash -c ' #!/bin/bash @@ -44,6 +44,11 @@ services: dex-trading-bot: build: context: . + args: + BUILDPLATFORM: ${BUILDPLATFORM:-amd64} + NEUTRON_VERSION: ${NEUTRON_VERSION:-latest} + image: dex-trading-bot:${NEUTRON_VERSION:-latest} + platform: linux/amd64 depends_on: - "neutron-node" entrypoint: ["/bin/bash", "./scripts/setup_entrypoint.sh"] From 47f6a5fedcf4812a7649cca92b1f38562c19dd45 Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Fri, 18 Oct 2024 10:01:57 +1000 Subject: [PATCH 27/34] chore: update Docker CLI version --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 6ba82b0..2b49bae 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,7 @@ ARG NEUTRON_IMAGE=neutron-${BUILDPLATFORM}:${NEUTRON_VERSION} FROM --platform=${BUILDPLATFORM} ${NEUTRON_IMAGE} AS neutrond-binary # allow this container to contact other Docker containers through the docker CLI -FROM --platform=${BUILDPLATFORM} docker:24.0.5-cli +FROM --platform=${BUILDPLATFORM} docker:27.3.1-cli # add additional dependencies for the testnet scripts RUN apk add bash curl grep jq; From 92b7e8baceb5541814c04a2f3e78fa5eacb5cc87 Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Fri, 18 Oct 2024 10:02:14 +1000 Subject: [PATCH 28/34] refactor: use recommended CMD syntax --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 2b49bae..a7a8099 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,4 +22,4 @@ COPY --from=neutrond-binary /bin/neutrond /usr/bin WORKDIR /workspace/neutron COPY scripts /workspace/neutron/scripts -CMD bash ./scripts/run_trade_bot.sh +CMD ["bash", "./scripts/run_trade_bot.sh"] From 85411141dd616caa3a0437d6db51774f45b00842 Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Fri, 18 Oct 2024 10:02:45 +1000 Subject: [PATCH 29/34] feat: add more checking delay: startup is a bit slower now --- scripts/check_chain_status.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/check_chain_status.sh b/scripts/check_chain_status.sh index ae519b1..66a5587 100644 --- a/scripts/check_chain_status.sh +++ b/scripts/check_chain_status.sh @@ -28,7 +28,7 @@ abci_info=$( --max-time 3 \ --retry 30 \ --retry-connrefused \ - --retry-delay 1 \ + --retry-delay 2 \ --silent \ $RPC_ADDRESS/abci_info ) From b301e3803d51f3e12603cfec1bb4b3088d3414d4 Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Fri, 18 Oct 2024 10:03:31 +1000 Subject: [PATCH 30/34] feat: update to most current production release --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7ce1cb1..564d603 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ REPOS_DIR ?= ./repos SETUP_DIR ?= $(REPOS_DIR)/neutron-integration-tests/setup DOCKER ?= docker COMPOSE ?= docker-compose -NEUTRON_VERSION ?= v2.0.2 +NEUTRON_VERSION ?= v4.2.2 GAIA_VERSION ?= v14.1.0 From db52a2b6320393455a51c4e25efddefec8801cab Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Fri, 18 Oct 2024 10:04:56 +1000 Subject: [PATCH 31/34] feat: update to Neutron v5 API --- Makefile | 2 +- scripts/run_trade_bot.sh | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 564d603..fcfbafb 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ REPOS_DIR ?= ./repos SETUP_DIR ?= $(REPOS_DIR)/neutron-integration-tests/setup DOCKER ?= docker COMPOSE ?= docker-compose -NEUTRON_VERSION ?= v4.2.2 +NEUTRON_VERSION ?= v5.0.0-rc0 GAIA_VERSION ?= v14.1.0 diff --git a/scripts/run_trade_bot.sh b/scripts/run_trade_bot.sh index 732ba29..ec219c6 100644 --- a/scripts/run_trade_bot.sh +++ b/scripts/run_trade_bot.sh @@ -282,6 +282,8 @@ do "$( get_joined_array $tick_count get_fee "$fees" )" \ `# disable_autoswap` \ "$( repeat_with_comma "true" "$tick_count" )" \ + `# fail_tx_on_BEL` \ + "$( repeat_with_comma "true" "$tick_count" )" \ `# options` \ --from $person --yes --output json --broadcast-mode sync --gas auto --gas-adjustment $GAS_ADJUSTMENT --gas-prices $GAS_PRICES )" @@ -312,7 +314,7 @@ do echo "check: place-limit-order: tokenA side: is $first_tickA_price_ratio > $goal_price_ratio ?" if [ "$first_tickA_price_ratio" != "null" ] && (( $( bc <<< "$first_tickA_price_ratio > $goal_price_ratio" ) )) then - balance_amount="$( neutrond query bank balances $address --denom $tokenB --output json | jq -r ".amount" )" + balance_amount="$( neutrond query bank balance $address "$tokenB" --output json | jq -r ".balance.amount // 0" )" trade_amount="$( echo "$balance_amount" | jq -r "(. | tonumber) * $swap_factor | floor" )" echo "making place-limit-order: '$tokenB' -> '$tokenA' to goal price $goal_price with $trade_amount tokens" directional_goal_price="$(( $goal_price * -1 ))" @@ -358,7 +360,7 @@ do echo "check: place-limit-order: tokenB side: is $first_tickB_price_ratio < $goal_price_ratio ?" if [ "$first_tickB_price_ratio" != "null" ] && (( $( bc <<< "$first_tickB_price_ratio < $goal_price_ratio" ) )) then - balance_amount="$( neutrond query bank balances $address --denom $tokenA --output json | jq -r ".amount" )" + balance_amount="$( neutrond query bank balance $address "$tokenA" --output json | jq -r ".balance.amount // 0" )" trade_amount="$( echo "$balance_amount" | jq -r "(. | tonumber) * $swap_factor | floor" )" echo "making place-limit-order: '$tokenA' -> '$tokenB' to goal price $goal_price with $trade_amount tokens" directional_goal_price="$goal_price" @@ -483,6 +485,8 @@ do "$( get_joined_array $excess_user_deposits_count get_fee "$fees" )" \ `# disable_autoswap` \ "$( repeat_with_comma "true" "$excess_user_deposits_count" )" \ + `# fail_tx_on_BEL` \ + "$( repeat_with_comma "false" "$excess_user_deposits_count" )" \ `# options` \ --from $person --yes --output json --broadcast-mode sync --gas auto --gas-adjustment $GAS_ADJUSTMENT --gas-prices $GAS_PRICES )" From 71a660ef9de606527dce3410877ef1ab39e8967d Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Fri, 18 Oct 2024 11:08:52 +1000 Subject: [PATCH 32/34] feat: only delay loops after the first loop --- scripts/run_trade_bot.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/run_trade_bot.sh b/scripts/run_trade_bot.sh index ec219c6..14fc500 100644 --- a/scripts/run_trade_bot.sh +++ b/scripts/run_trade_bot.sh @@ -116,6 +116,7 @@ function check_duration { } # respond to price changes forever +loop_index="0" while true do # wait a bit, maybe less than a block or enough that we don't touch a block or two @@ -127,8 +128,12 @@ do break fi - echo "... loop will delay for: $delay seconds" - sleep $delay + # delay loops after the first loop + if [ "$loop_index" -gt "0" ] + then + echo "... loop will delay for: $delay seconds" + sleep $delay + fi echo "loop: starting at $EPOCHSECONDS" for (( pair_index=0; pair_index<$token_pair_config_array_length; pair_index++ )) @@ -546,6 +551,7 @@ do done + loop_index+=1 done echo "TRADE_DURATION_SECONDS has been reached"; From 2429d21ded3757b44619623d8b9b9fd6394ea616 Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Wed, 20 Nov 2024 00:28:16 +1000 Subject: [PATCH 33/34] fix: increment loop properly --- scripts/run_trade_bot.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/run_trade_bot.sh b/scripts/run_trade_bot.sh index 14fc500..f2344c9 100644 --- a/scripts/run_trade_bot.sh +++ b/scripts/run_trade_bot.sh @@ -551,7 +551,7 @@ do done - loop_index+=1 + loop_index="$(( $loop_index + 1 ))" done echo "TRADE_DURATION_SECONDS has been reached"; From 71a945cd04cbb28a2f123a1fa8c8a0d1118911e7 Mon Sep 17 00:00:00 2001 From: David Uhlmann Date: Mon, 25 Nov 2024 22:41:03 +1000 Subject: [PATCH 34/34] fix: the closest piece of liquidity may be a pool or a limit order --- scripts/run_trade_bot.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/run_trade_bot.sh b/scripts/run_trade_bot.sh index f2344c9..6466c69 100644 --- a/scripts/run_trade_bot.sh +++ b/scripts/run_trade_bot.sh @@ -313,7 +313,7 @@ do echo "making query: of current '$tokenA' ticks" first_tickA_price_ratio=$( neutrond query dex list-tick-liquidity "$tokenA<>$tokenB" "$tokenA" --output json --limit 1 \ - | jq -r ".tick_liquidity[0].pool_reserves.price_taker_to_maker" + | jq -r ".tick_liquidity[0].pool_reserves.price_taker_to_maker // .tick_liquidity[0].limit_order_tranche.price_taker_to_maker" ) # use bc for aribtrary precision math comparison (check for null because non-zero result evals true) echo "check: place-limit-order: tokenA side: is $first_tickA_price_ratio > $goal_price_ratio ?" @@ -360,7 +360,7 @@ do echo "making query: of current '$tokenB' ticks" first_tickB_price_ratio=$( neutrond query dex list-tick-liquidity "$tokenA<>$tokenB" "$tokenB" --output json --limit 1 \ - | jq -r ".tick_liquidity[0].pool_reserves.price_opposite_taker_to_maker" + | jq -r ".tick_liquidity[0].pool_reserves.price_opposite_taker_to_maker // .tick_liquidity[0].limit_order_tranche.maker_price" ) echo "check: place-limit-order: tokenB side: is $first_tickB_price_ratio < $goal_price_ratio ?" if [ "$first_tickB_price_ratio" != "null" ] && (( $( bc <<< "$first_tickB_price_ratio < $goal_price_ratio" ) ))