Skip to content

dasein108/aerodrome-lp-studio

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

aerodrome-lp-studio

Related articles: The Agentic Quant Desk · Part 1: Building the Harness

Aerodrome (Base) LP management + sniping primitives, with a dashboard — in one repo. Discover pools, read gauge emissions, compute position PnL & impermanent loss, mint/stake/remove on-chain, and see it all in a Streamlit UI.

Extracted from a private trading desk. Mechanics only — pool discovery, gauge/PnL/IL reads, an on-chain executor, and a dashboard. The tuned sniping selection, range-sizing, and rebalance triggers (the edge) stay private; sniping is shown here as primitives + a trivial example rule you replace.

Two halves, one install

src/aero_lp/          on-chain primitives
                      pool discovery · gauge/emission · PnL & IL · mint/stake/remove executor
                      deployment registry · math · backtest CL valuation

src/aero_dashboard/   Streamlit UI
                      JSONL loaders · equity/drawdown/metrics components
                      metrics.py SessionAnalyzer · live.py glue → aero_lp

examples/             manage_demo.py (live PnL) · snipe_demo.py (rank + dry-run mint)
                      backtest_lp.py (offline sim) · sample-snapshots/ (demo data)

pip install -e . gives you both: import aero_lp to act on-chain, aero-dashboard (or streamlit run) to visualize.

Run the dashboard (offline, no keys)

pip install -e .
streamlit run src/aero_dashboard/app.py   # 3 bundled samples: equity, drawdown, metrics, hedge

Encrypted wallet (recommended for live)

Keys are encrypted at rest (Ethereum keystore — scrypt + AES-128-CTR). Only the password is needed at runtime; no plaintext key ever touches disk or the env.

python -m aero_lp.aerodrome.cli_keystore generate  # new wallet → keystore (prompts password)
python -m aero_lp.aerodrome.cli_keystore encrypt   # or encrypt a key you already have
python -m aero_lp.aerodrome.cli_keystore info      # show address (no decrypt)
python -m aero_lp.aerodrome.cli_keystore verify    # test decryption

Default keystore file is base_wallet.json (override with KEYSTORE_PATH). At runtime:

export KEYSTORE_PASSWORD='...'   # only secret in the env; key stays encrypted on disk

The executor resolves a key automatically, in order: explicit private_key=encrypted keystore (KEYSTORE_PATH + KEYSTORE_PASSWORD) → plaintext BASE_PRIVATE_KEY. So once the keystore + password are set, construct AerodromeExecutor(...) with no private_key= and it signs from the keystore.

Helpers are re-exported for convenience:

from aero_lp import load_key, get_keystore_address, get_default_wallet_address
addr = get_default_wallet_address()   # read address without decrypting

.gitignore already excludes *keystore*.json and base_wallet*.json. A generated wallet still needs manual funding (ETH for gas + pair tokens on Base).

Manage / snipe (live — needs an RPC)

from aero_dashboard.live import live_positions_frame   # toolkit → dashboard frame
df = live_positions_frame(rpc_url, [{"token_id": 1073536, "gauge": "0x61E0B104..."}])
# df has equity_usd, il_pct, in_range, aero_per_day — render it in the dashboard

from aero_lp import GaugeMonitor, AerodromeExecutor, SLIPSTREAM_V3_CONTRACTS
gm = GaugeMonitor(rpc_url=rpc)   # read emissions / PnL
ex = AerodromeExecutor(          # mint/stake (dry-run)
    dry_run=True, nfpm_address=SLIPSTREAM_V3_CONTRACTS["nfpm"], rpc_url=rpc,
)

See examples/manage_demo.py and examples/snipe_demo.py. Writes default to dry-run; supply RPC + keystore/private key (.env.example) to send. Verify gauge.nft() == executor.nfpm before staking a migrated pair.

How the halves connect

The dashboard reads the same snapshot schema the toolkit (and the private bots) produce. live.py is the bridge: it calls aero_lp.GaugeMonitor.get_position_pnl(...) and shapes the result into the exact DataFrame the dashboard components render — so the same UI shows backtest samples (offline) or your live book (RPC).

Run a real strategy

Full walkthrough — discover → range → mint → stake → monitor → rebalance → exit — for WETH/cbBTC CL50 using either an S1-style sniper (emission-ranked entry) or an S17-style directional LP (hold + rebalance): docs/running-lp-strategies.md.

Backtest (offline, no keys)

A CL valuation engine ships in aero_lp.backtest (position value as price moves, IL vs HODL) and a session scorer in aero_dashboard.SessionAnalyzer (return, Sharpe, drawdown, time-in-range, rebalance efficiency — the same metrics used on paper/live data). What's not shipped is the price feed and the rebalance rule — those are yours (real candles + your edge).

python examples/backtest_lp.py   # synthetic price path → snapshots.jsonl → printed metrics
# → return / sharpe / max drawdown / time-in-range / rebalances, renderable in the dashboard
from aero_lp.backtest import LPPosition, create_position, hodl_value
pos = create_position(price=20.0, capital_usd=10_000, range_width_ticks=10, tick_spacing=50, ts=0)
v   = pos.value_at(22.0)               # CL value at a new price
il  = v - hodl_value(10_000, 20.0, 22.0)   # LP vs holding the tokens (impermanent loss)

from aero_dashboard import SessionAnalyzer
SessionAnalyzer.load("examples/sample-snapshots/sharpe-optimal-hedge").summary()  # score a run

Runnable examples, same engine, one per strategy family:

  • examples/backtest_lp.pyS1 sniper: neutral centered range, re-center on out-of-range.
  • examples/backtest_s17.pyS17 directional: asymmetric range placement (create_position(direction=, offset_pct=)) leaned by a stub momentum signal + TP/SL exits.
  • examples/backtest_s2_hedge.pyS2 / Sharpe-hedge delta-neutral: LP + perp short, sweeping hedge ratio h ∈ {0, h*, 1}. The Sharpe-optimal h* is the closed-form compute_h_star (Hane 2026), clamped at 0.70 — the same h_actual=0.7 the dashboard's hedge sample-snapshots show.
  • examples/backtest_compare.py — S1 vs S17 vs HODL on one path; walk_forward.py — many windows.

All examples fetch real Bybit prices (public klines, no API key) and fall back to synthetic GBM only if offline:

from aero_lp.backtest import pair_price_path
prices = pair_price_path("WETH", "cbBTC", "1h", 240)   # → ETHBTCUSDT closes (cross-pair)
prices = pair_price_path("WETH", "USDC",  "1h", 240)   # → ETHUSDT closes (direct)

Pair→symbol resolution mirrors the live desk: direct (X/stable → that symbol), cross (WETH/cbBTC → ETHBTCUSDT), synthetic (ratio of two USDT legs).

Walk-forward (examples/walk_forward.py) — one path is one noisy number; slice a long history into many windows and judge against the distribution:

from aero_lp.backtest import pair_price_path, sliding_windows, bootstrap_windows, summarize
prices = pair_price_path("WETH", "USDC", "1h", 1000)
rets = [run_s1(w) for w in sliding_windows(prices, window=168, stride=24)]  # 7d win, 1d step
summarize(rets)   # → {mean, median, p5, p95, win_rate, ...}

Your own signal/rule still replaces the stubs. (scenario_builder regime labelling / signal-driven sims / tuned policies stay private.)

Real APR, not a guess (examples/live_apr_backtest.py): emission APR is range/time-specific, so fetch it from a live position rather than hardcoding —

from aero_lp import GaugeMonitor
from aero_lp.backtest import live_position_apr   # = aero_per_day_usd * 365 / position_value_usd
apr = live_position_apr(GaugeMonitor(rpc_url=RPC), token_id, gauge)["apr_pct"]   # e.g. 192%

live_gauge_inputs(...) returns the liquidity-share inputs (gauge AERO/day, AERO price, active-tick TVL) for range-sweeps; GaugeMonitor.rank_pools_by_emission(t0, t1) gives APR for pools you haven't entered.

What's deliberately out

The tuned sniping logic — snipe_engine (efficiency scoring / pool selection), vol_range (adaptive range sizing), the rebalance/dust triggers, and the backtest's tuned layer (scenario_builder regime construction, signal-driven sims, rebalance policies). Those are the alpha. You get the primitives + a "pick the highest-emission pool" / "re-center on OOR" stub to replace with your own.

Test

pip install -e ".[dev]" && pytest   # primitives + IL math + dashboard render + alpha-absence

License

MIT.

About

Aerodrome (Base) LP management + sniping primitives with a Streamlit dashboard — pool discovery, gauge emissions, PnL & impermanent-loss reads, and an on-chain mint/stake/remove executor.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages