This repository contains simple DeFi bots in Typescript, which are designed to find and take advantage of arbitrage opportunities in different SUI DEXs and/or perform trading activities based on script-logic strategies. Since it is still in BETA version, the agents might not be profitable and are mainly open-sourced as a reference implementation that could be reused to implement custom strategies.
- Implements a basic
Strategy
interface (developers can implement their own strategies). - Provides three basic trading strategies as reference implementations (described later in this Readme).
- Automatically executes trades when it finds profitable opportunities.
- Supports multiple cryptocurrencies and trading pairs; currently supporting trading on three Sui DEXs.
- Supports receiving data from multiple sources, including swap pools and external sources like Binance. Currently, the bot utilizes feeds from CCTX (CryptoCurrency eXchange Trading Library) to get the latest prices from Binance. Note that CCTX supports Binance, Bitget, Coinbase, Kraken, KuCoin and OKX, and it is straight-forward to accept feeds from these CEXs as well.
In Capy Trading Bot, strategies subscribe to relevant data sources and create trade orders based on the information they get. Every second, Capy Trading Bot requests new data points from each data source. When it receives a new data point, Capy Trading Bot sends it to subscribing strategies which return trade orders to Capy Trading Bot. Capy Trading Bot submits transactions to the relevant swap pools modules to execute these trade orders. If a strategy returns multiple trade orders, Capy Trading Bot submits them as a single transaction.
sequenceDiagram
Strategy->>Capybot: Subscribe to relevant data sources
activate Capybot
loop Every second for each data source
Capybot->>+DataSource: Request new data point
DataSource->>DataSource: Call external API
DataSource->>-Capybot: New data point
loop For each subscribing strategy
Capybot->>+Strategy: New data point
Strategy->>-Capybot: Trade orders
Capybot->>Capybot: Submit trade orders as a single transaction block
end
end
deactivate Capybot
Capy Trading Bot supports the following three trading strategies:
Arbitrage
: This strategy looks for arbitrage opportunities in chains of two or more swap pools across different DEXs. It computes the product of the prices along the chain of swap pools, say SUI -> USDC -> CETUS -> SUI, and if the product is different from 1 it means there is an arbitrage opportunity.RideTheTrend
: This strategy looks for trend following opportunities in a single swap pool by comparing a short moving average with a longer moving average to get an indication whether the price is going up or down.MarketDifference
: This strategy compares the relative price of a token pair in a swap pool with the price of the same pair on an exchange, such as Binance. If the price differs, the strategy suggests to either go long or short a given token.
Strategies are located in the src/strategies
folder, and each strategy extends the Strategy
class which requires the
evaluate
method to be implemented. The evaluate
method is called every second with the latest data point from the
data sources and should return a (potentially empty) array of trade orders.
To add other strategies, you can implement them as described above and add it to Capy Trading Bot by calling capybot.addStrategy
in src/index.ts
.
Capy Trading Bot can leverage two different types of data sources: Swap pools and external sources. Capy Trading Bot can execute trades via swap pools, and swap pools provide the current token price in the pool. External data sources can provide additional data that could be useful inputs to trading strategies.
In this release, Capy Trading Bot supports swap pools from Cetus, Turbos and Suiswap, and uses Binance (via CCTX) as an external data source for the relative prices of some token pairs.
- Clone this repository.
- Install dependencies with
yarn install
.
Before you run the script, environment variables need to be set: an ADMIN_PHRASE
and an ADMIN_ADDRESS
for each pool
being traded on.
Note that each pool require a unique phrase/address combination, which must not be shared between pools.
If they are shared, it is possible that a concurrent submission of multiple transactions using the same e.g. gas object may lock that object until the end of the current epoch, causing any of the bot's future transactions to fail at the execution stage.
Note that in the case of RAMM pools, which support more than 2 assets, a phrase and an address need to be set for each
separate instance of Pool
:
- If a
SUI/USDC/USDT
pool is being used twice- once for its
SUI/USDC
pair, and - once again for its
SUI/USDTR
pair there must be a total of 2 phrases/address pairs, one pair for each of the above pools.
- once for its
The ADMIN_PHRASE
is the passphrase for the keypair a certain pool will use when trading, and its
corresponding ADMIN_ADDRESS
will then be the hexadecimal address of its account.
They can be exported with the following commands in the terminal:
export ADMIN_PHRASE="your_passphrase_here"
export ADMIN_ADDRESS="your_address_here"
If on Unix-like operating systems, usage of direnv
is recommended instead,
with an .envrc
file at the root of the capybot
repository defining phrase/address pairs for
every pool to be used.
This step is not sufficient, and necessary for the bot to work.
On the following snippet of pseudo-code, 3 pools are declared
const USDCtoSUI = new Pool('0x0...1', coins.USDC, coins.SUI)
const USDTtoSUI = new Pool('0x0...2', coins.USDT, coins.SUI)
const USDCtoUSDT = new Pool('0x0...3', coins.USDC, coins.USDT)
To execute a triangular arbitrage strategy, a trader makes 3 transactions: first, exchange the original token for another one (i.e. SUI -> USDC); second, swap the second token for a third one (i.e. USDC -> USDT); and third, trade the third token back to the original one (i.e. USDT -> SUI).
On the following snippet of code we add a triangular arbitrage strategy to the capybot.
// Add triangular arbitrage strategy: USDC/SUI -> (USDT/SUI)^-1 -> (USDC/USDT)^-1.
capybot.addStrategy(
new Arbitrage(
[
{
pool: SUItoUSDC.uri,
a2b: true,
},
{
pool: USDCtoUSDT.uri,
a2b: true,
},
{
pool: USDTtoSUI.uri,
a2b: true,
},
],
defaultAmount[coins.SUI],
ARBITRAGE_RELATIVE_LIMIT,
'Arbitrage: SUI -> USDC -> USDT -> SUI'
)
)
ARBITRAGE_RELATIVE_LIMIT
represents the relative limit. e.g. 1.05 for a 5% win.
Ride the trend strategy is a trading technique that involves following the direction of the market movement and staying in a position until the trend reverses. The idea is to capture as much profit as possible from a strong and sustained price movement. To apply this strategy, traders need to identify the trend using technical indicators, such as moving averages and enter a trade when the price confirms the trend.
On the following snippet of code, we add a Ride The Trend strategy to the capybot.
capybot.addStrategy(
new RideTheTrend(
SUItoUSDC.uri,
5,
10,
[
defaultAmount[SUItoUSDC.coinTypeA],
defaultAmount[SUItoUSDC.coinTypeB],
],
RIDE_THE_THREAD_LIMIT,
'RideTheTrend (SUI/USDC)'
)
)
It takes six parameters as input:
- pool: The address of the pool to watch.
- short: The length of the short moving average (in seconds).
- long: The length of the long moving average (in seconds).
- defaultAmounts: An array of two numbers, representing the amount of tokens to swap of coin type A and B respectively when the trend changes.
- limit: A number between 0 and 1, representing the percentage of profit or loss to accept before executing a swap. For example, 1.05 means a 5% profit margin.
- name: A human-readable name for this strategy.
It calculates the moving averages of the pool price and it then compares the short and long moving averages to determine the trend direction. When the trend changes, it executes a swap, with the specified swap amounts and relative limit.
The bot can also use external data sources. For example, if there is a price discrepancy between Binance and a SUI DEX, the bot can arbitrage by buying/selling tokens on the DEX.
On the following snippet of code, we create a new market difference strategy. This strategy compare prices between a pool and various exchanges and will buy the token that is too cheap and sell the token that is too expensive.
capybot.addStrategy(
new MarketDifference(
WBTCtoUSDC,
'BinanceBTCtoUSDC',
[defaultAmount[coins.WBTC], defaultAmount[coins.USDC]],
ARBITRAGE_RELATIVE_LIMIT,
'Market diff: (W)BTC/USDC, Binance vs DEX'
)
)
The following parameters are required:
- pool: The pool to monitor for price changes.
- exchange: The exchange to compare with the pool. It should offer the same trading pairs as the pool.
- defaultAmounts: The default amounts of tokens to trade when the price difference exceeds the limit.
- limit: The relative threshold for the price difference. A trade will be executed if the price difference is greater than this value.
- For example, a value of 1.05 means that the price difference should be at least 5%.
- name: A human-readable name for this strategy.
Build the project with yarn build
Run the script with yarn start
This will run the bot for one hour.
To run the bot for longer, the duration
value, in the call to capybot.loop
in src/index.ts
, must be changed.
The Capybot Monitor is a collection of Python scripts to monitor the status of a running instance of a Capybot. It produces live updated plots like the following which shows the price development for the swap pools the given Capybot was trading where 1 is the price when the bot was started.
Installation instructions are available on the Capybot Monitor repository.
The table below lists all the pools for the currently supported DEXs:
DEX | Coin A - CoinB | Pool |
---|---|---|
CETUS | USDT - USDC | 0xc8d7a1503dc2f9f5b05449a87d8733593e2f0f3e7bffd90541252782e4d2ca20 |
SUI - USDC | 0xcf994611fd4c48e277ce3ffd4d4364c914af2c3cbb05f7bf6facd371de688630 | |
CETUS - SUI | 0x2e041f3fd93646dcc877f783c1f2b7fa62d30271bdef1f21ef002cebf857bded | |
WETH - USDC | 0x5b0b24c27ccf6d0e98f3a8704d2e577de83fa574d3a9060eb8945eeb82b3e2df | |
SUI - USDT | 0xa96b0178e9d66635ce3576561429acfa925eb388683992288207dbfffde94b65 | |
WSOL - SUI | 0x014abe87a6669bec41edcaa95aab35763466acb26a46d551325b07808f0c59c1 | |
RAMM | SUI - USDT | 0xcb6640194b37023f6bed705f40ff22883eb6007d4c69e72c317c64671f9f6b29 |
SUI - USDC | 0xcb6640194b37023f6bed705f40ff22883eb6007d4c69e72c317c64671f9f6b29 |
Contributions are welcome! Please open an issue or pull request if you have any suggestions or improvements.