Skip to main content

Overview

This guide walks you through running the canonical ANK example: a cross-protocol leverage loop that borrows ETH from Aave, stakes it in Lido for wstETH, deposits the wstETH back to Aave as collateral, and repeats the process to reach a target loan-to-value (LTV) ratio.
1

Create a configuration file

Create a file named sim.yaml with the following contents:
sim.yaml
steps: 24
start_ts: 1725000000   # unix seconds (no underscores)
user: 1
log_level: INFO
risk_out_csv: "risk_out.csv"

leverage:
  token: 1                   # borrow ETH
  initial_deposit_units: 10000
  target_ltv_bps: 7000       # 70%
  band_bps: 250              # ±2.5%
# prices_csv: "prices.csv"   # optional: price path override
Configuration breakdown:
  • steps: Number of ticks to simulate (24 in this example)
  • start_ts: Simulation start time in Unix seconds (plain integer, no underscores)
  • user: User ID for the simulation
  • leverage.target_ltv_bps: Target LTV in basis points (7000 = 70%)
  • leverage.band_bps: Rebalancing band (250 = ±2.5%)
2

Run the simulation

Execute the simulation using the ANK CLI:
cargo run -p ank-cli --bin ank-cli -- --config sim.yaml
If you see error: cargo run could not determine which binary to run, make sure to use --bin ank-cli to specify the binary explicitly.
3

Observe the execution

You should see output similar to:
[INFO] tick step=0 ts=1725000000 bundles=2 txs_ok=3 txs_rej_gas=0
[INFO] tick step=1 ts=1725000001 bundles=1 txs_ok=2 txs_rej_gas=0
[INFO] tick step=2 ts=1725000002 bundles=1 txs_ok=2 txs_rej_gas=0
...
What’s happening:
  • Tick 0: Initial stake of ETH to receive wstETH, then deposit wstETH to Aave as collateral
  • Each subsequent tick:
    • Sync Aave’s wstETH price from Lido exchange rate × ETH price
    • Controller checks current LTV:
      • Below bandborrow ETH → stake to Lido → deposit wstETH (next tick)
      • Above bandrepay debt; if wallet ETH is insufficient → withdraw wstETH → unstakerepay (mandatory unwind)
4

Review the risk output

Open risk_out.csv to see per-tick metrics:
ts,wallet_value_e18,deposit_value_e18,debt_value_e18,net_value_e18,ltv_bps,hf_bps,deposits_units,debt_units,drawdown_e18
1725000000,0,20000000000000000000000,0,20000000000000000000000,0,0,10000,0,0
1725000001,0,20000000000000000000000,14000000000000000000000,6000000000000000000000,7000,11428,10000,7000,0
1725000002,0,20140000000000000000000,14000000000000000000000,6140000000000000000000,6965,11484,10070,7000,0
...
SUMMARY,min_hf_bps,max_hf_bps,max_drawdown_e18,vol_e18,ticks
,11428,30000,500000000000000000,250000000000000000,24
Key columns:
  • ltv_bps: Current loan-to-value in basis points
  • hf_bps: Health factor in basis points (10000 = 1.0; below 10000 triggers liquidation)
  • net_value_e18: Wallet + deposits - debt in 1e18 units
  • drawdown_e18: Maximum drawdown from peak net value
The summary rows at the end show aggregate metrics like min/max health factor, max drawdown, and volatility.

Understanding the strategy

The leverage loop strategy automatically manages your LTV:
// Simplified pseudocode of the leverage controller
let current_ltv = debt_value / collateral_value;
let target_ltv = 0.70; // 70%
let band = 0.025;      // ±2.5%

if current_ltv < target_ltv - band {
    // Below target: add leverage
    // 1. Borrow more ETH from Aave
    // 2. Stake ETH in Lido → receive wstETH
    // 3. Deposit wstETH to Aave (next tick)
} else if current_ltv > target_ltv + band {
    // Above target: reduce leverage
    // 1. If wallet has ETH → repay directly
    // 2. Else → withdraw wstETH → unstake → repay
}

Adding price shocks

You can stress-test your strategy by providing custom price paths:
1

Create a price CSV

Create prices.csv with the following structure:
prices.csv
ts,token,price_e18
1725000000,1,2000000000000000000000
1725000000,3,2000000000000000000000
1725000100,1,1600000000000000000000  # 20% ETH crash at t+100
1725000200,1,2200000000000000000000  # Recovery to $2200
  • Column 1 (ts): Unix timestamp
  • Column 2 (token): Token ID (1 = ETH, 3 = wstETH)
  • Column 3 (price_e18): Price in 1e18 units (2000e18 = $2000)
2

Update your config

Uncomment the prices_csv line in sim.yaml:
sim.yaml
steps: 24
start_ts: 1725000000
user: 1
log_level: INFO
risk_out_csv: "risk_out.csv"
prices_csv: "prices.csv"  # Enable price override

leverage:
  token: 1
  initial_deposit_units: 10000
  target_ltv_bps: 7000
  band_bps: 250
3

Rerun the simulation

cargo run -p ank-cli --bin ank-cli -- --config sim.yaml
The engine will now use your custom prices instead of static protocol prices. Watch how the health factor responds to the price shock in risk_out.csv.

Next steps

Parameter optimization

Use the optimize binary to sweep target LTV, bands, and initial deposits

Protocol reference

Learn about Aave, Lido, Uniswap, and Pendle protocol APIs

Custom strategies

Build your own strategy using the planner closure pattern

Risk analytics

Deep dive into LTV, health factor, drawdown, and volatility calculations

Build docs developers (and LLMs) love