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

Fix position deviation calculation by using price instead of sqrt price #821

Merged
merged 11 commits into from
Mar 18, 2025
5 changes: 5 additions & 0 deletions .changeset/sour-ideas-jam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@orca-so/whirlpools-example-rust-repositioning-bot": patch
---

Fix calculation of position deviation
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

57 changes: 41 additions & 16 deletions examples/rust-sdk/whirlpool_repositioning_bot/README.md
Original file line number Diff line number Diff line change
@@ -1,50 +1,68 @@
# Whirlpool Repositioning Bot

A Rust-based CLI bot for interacting with the Orca Whirlpools program on Solana. This bot monitors and rebalances a liquidity position by closing and reopening positions when price deviations exceed a user-defined threshold.

> NOTE: this example works with SPL tokens only. If you want to use the repositioning bot on pools where tokens are paired with SOL, you should ensure that you have wSOL (`So11111111111111111111111111111111111111112`) available in your wallet. Check out [this guide](https://solana.com/developers/cookbook/tokens/manage-wrapped-sol) on how to use wSOL.

---

## Features

- **Automated Position Monitoring**: Monitors price deviation of a liquidity position on Orca Whirlpool by calculating the center of the position's price range and comparing it to the current pool price. If the deviation exceeds the specified threshold (in percentage), the bot initiates rebalancing.
- **Automated Rebalancing**: Closes and reopens liquidity positions by centering the new position around the current pool price, maintaining the same width (distance between the lower and upper price bounds) as the initial position.
- **Customizable Priority Fees**: Integrates compute budget priority fees to enhance transaction speed and landing, with options ranging from `none` to `turbo` for different levels of prioritization.

---

## Prerequisites

1. **Solana Wallet**:
- Place a `wallet.json` file in the working directory with the keypair that owns the positions.
- Ensure the wallet has sufficient funds for transactions.

- Place a `wallet.json` file in the working directory with the keypair that owns the positions.
- Ensure the wallet has sufficient funds for transactions.

2. **Existing Position**:
- You must have an active position on Orca Whirlpools. You can open a position using our SDKs or through our UI at https://www.orca.so/pools.

- You must have an active position on Orca Whirlpools. You can open a position using our SDKs or through our UI at https://www.orca.so/pools.

3. **Rust**:
- Install Rust using [rustup](https://rustup.rs/).

- Install Rust using [rustup](https://rustup.rs/).

---

## Installation

1. Clone this repository:
```bash
git clone https://github.com/orca-so/whirlpools.git
cd examples/rust-sdk/whirlpool_repositioning_bot
```

```bash
git clone https://github.com/orca-so/whirlpools.git
cd examples/rust-sdk/whirlpool_repositioning_bot
Copy link
Collaborator

Choose a reason for hiding this comment

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

We've not received any response from this dev, but I guess it is nice to run yarn run build at the root.

Our "working" directory has generated crate, so this procedure works.
But what happens if we clone the repository at a new place.

https://discord.com/channels/798712664590254081/1049776001367949413/1349564173893374014

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Building the entire repo with yarn build from root can maybe be a bit overkill? For some users, that also causes issues if they're not using the correct version of Rust. Also, if devs want to continue building from this reference example, they will most likely use it in a new repo.

A few lines below this comment in the README there is a note to change the reference to the dependency from local to the versions.

2. Update `Cargo.toml`
   This project uses the local version of the dependencies. If you want to move this example project outside of this repo, update the `Cargo.toml`:

---
# other dependencies
orca_whirlpools = { version = "^2.0" }
orca_whirlpools_client = { version = "^2.0" }
orca_whirlpools_core = { version = "^2.0" }
---

Maybe it's more user friendly to have devs update the cargo.toml?

Copy link
Collaborator

Choose a reason for hiding this comment

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

that also causes issues if they're not using the correct version of Rust.

good point.

Before even considering running it outside of this repository, simply cloning the repository and running cargo build results in an error because generated does not exist.

Therefore, it would be helpful to either include instructions to modify the dependencies or provide an option to switch dependencies within Cargo.toml. (If the latter is a bit difficult, instructing users to modify Cargo.toml manually could be a viable approach.)

In any case, users who want to work with the SDK expect it to run smoothly, so reducing potential stumbling points would be beneficial.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The suggested option to switch dependencies within Cargo.toml is nice. However, I was not able to get that to work without errors.

For now, I will leave it like this:

  • I improved the README, explaining that there are two ways to build and use this project:

    • build from root
    • build the project only
  • I added comments in the Cargo.toml.

```

2. Update `Cargo.toml`
This project uses the local version of the dependencies. If you want to move this example project outside of this repo, update the `Cargo.toml`:
This project uses the local version of the dependencies. If you want to move this example project outside of this repo, update the `Cargo.toml`:

```toml
# other dependencies
orca_whirlpools = { version = "^1.0" }
orca_whirlpools_client = { version = "^1.0" }
orca_whirlpools_core = { version = "^1.0" }
orca_whirlpools = { version = "^2.0" }
orca_whirlpools_client = { version = "^2.0" }
orca_whirlpools_core = { version = "^2.0" }
# rest of the dependencies
```

3. Build the bot:
```bash
cargo build --release
```

```bash
cargo build --release
```

4. The executable will be located in target/release/whirlpool_repositioning_bot

---

## RPC Configuration

The bot connects to an SVM network by using an RPC URL. Make a local copy of `.env.template` to `.env` and set your RPC URL there. It is strongly recommended to you use a URL from an RPC provider, or your own RPC node.

```bash
Expand All @@ -54,7 +72,9 @@ RPC_URL="https://your-rpc-url.com"
---

## Usage

Run the bot with the following arguments

```bash
./target/release/lp-bot \
--position-mint-address <POSITION_MINT_ADDRESS> \
Expand All @@ -66,6 +86,7 @@ Run the bot with the following arguments
```

### Arguments

- `--position-mint-address` (required): The mint address of the position to monitor and rebalance.
- `--threshold` (optional): TThe threshold for triggering rebalancing, defined by how far the position's center deviates from the current price. Default: 100.
- `--interval` (optional): The time interval (in seconds) between checks. Default: 60.
Expand All @@ -79,13 +100,16 @@ Run the bot with the following arguments
- `slippage_tolerance_bps` (optional): Slippage tolerance in basis points (bps). Default: 100.

### Example Usage

Monitor and rebalance with default settings:

```bash
./target/release/lp-bot \
--position-mint-address 5m1izNWC3ioBaKm63e3gSNFeZ44o13ncre5QknTXBJUS
```

Monitor with custom threshold and interval:

```bash
./target/release/lp-bot \
--position-mint-address 5m1izNWC3ioBaKm63e3gSNFeZ44o13ncre5QknTXBJUS \
Expand All @@ -94,6 +118,7 @@ Monitor with custom threshold and interval:
```

Monitor with turbo priority fees:

```bash
./target/release/lp-bot \
--position-mint-address 5m1izNWC3ioBaKm63e3gSNFeZ44o13ncre5QknTXBJUS \
Expand All @@ -114,4 +139,4 @@ examples/
├── wallet.rs # Wallet management
├── position_manager.rs # Position monitoring and rebalancing
├── solana_utils.rs # RPC utilities
```
```
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,6 @@ pub async fn run_position_manager(
.await
.map_err(|_| "Failed to fetch Whirlpool data.")?;

let current_sqrt_price = whirlpool.sqrt_price;
let position_lower_sqrt_price = tick_index_to_sqrt_price(position.tick_lower_index);
let position_upper_sqrt_price = tick_index_to_sqrt_price(position.tick_upper_index);
let position_center_sqrt_price = (position_lower_sqrt_price + position_upper_sqrt_price) / 2;
let deviation_amount_sqrt = if current_sqrt_price > position_center_sqrt_price {
current_sqrt_price - position_center_sqrt_price
} else {
position_center_sqrt_price - current_sqrt_price
};
let deviation_bps = (deviation_amount_sqrt * 10000) / (position_center_sqrt_price);

let current_price = sqrt_price_to_price(
whirlpool.sqrt_price,
token_mint_a.decimals,
Expand All @@ -58,6 +47,13 @@ pub async fn run_position_manager(
);
let position_center_price = (position_lower_price + position_upper_price) / 2.0;

let deviation_amount = if current_price > position_center_price {
current_price - position_center_price
} else {
position_center_price - current_price
};
let deviation_bps = (deviation_amount * 10000.0) / (position_center_price);

println!("Current pool price: {:.6}", current_price);
println!(
"Position price range: [{:.6}, {:.6}]",
Expand Down
Loading