Skip to content

Bug/Derive the LP band's width cap from the pool's bin/tick granularity, not a flat percentage - #251

Open
lgrawet wants to merge 3 commits into
hummingbot:mainfrom
lgrawet:fix/lp-range-granularity-clamp
Open

lgrawet wants to merge 3 commits into
hummingbot:mainfrom
lgrawet:fix/lp-range-granularity-clamp

Conversation

@lgrawet

@lgrawet lgrawet commented Sep 22, 2026

Copy link
Copy Markdown

The band width was chosen from OHLCV volatility and clamped to a flat [4%, 20%], with the venue's bin/tick ceiling applied afterwards as a prose step — "shrink W until it fits" — that a tick can skip, and did. Two Orca opens at the identical 20.8% width landed 118 spacings on a tick_spacing=16 pool (opened fine) and 237 on a tick_spacing=8 pool (SIMULATION_FAILED, no funds moved, slot left empty). On Meteora the floor is the trap: a bin_step=10 pool caps the half-width at 3.40%, below the 4% floor, so a percent-first clamp is guaranteed to over-reach the hard 69-bin limit and fail the open.

W_max is now derived from the pool's own bin_step / tick_spacing and applied as the ceiling — W = min(clamp(ATR×2, 4%, 20%), W_max) — so the granularity cap binds instead of trailing. The fit table (68 bins / 120 spacings) ships in the lp_range_config skill, with the one-line solve for off-table pools, so no log arithmetic is left to the caller under a tick budget. A "4% floor" is explicitly void when W_max < 4%: a fine-grained pool cannot hold that band, and widening past W_max is what fails the open.

Stated in the skill, in the lp_slot_operator strategy that copies it, and in AGENT.md so the root summary no longer reads percent-first.

…not a flat percentage

The band width was chosen from OHLCV volatility and clamped to a flat [4%, 20%],
with the venue's bin/tick ceiling applied afterwards as a prose step — "shrink W
until it fits" — that a tick can skip, and did. Two Orca opens at the identical
20.8% width landed 118 spacings on a `tick_spacing=16` pool (opened fine) and 237
on a `tick_spacing=8` pool (SIMULATION_FAILED, no funds moved, slot left empty).
On Meteora the floor is the trap: a `bin_step=10` pool caps the half-width at
3.40%, below the 4% floor, so a percent-first clamp is guaranteed to over-reach
the hard 69-bin limit and fail the open.

`W_max` is now derived from the pool's own `bin_step` / `tick_spacing` and applied
as the ceiling — `W = min(clamp(ATR×2, 4%, 20%), W_max)` — so the granularity cap
binds instead of trailing. The fit table (68 bins / 120 spacings) ships in the
`lp_range_config` skill, with the one-line solve for off-table pools, so no log
arithmetic is left to the caller under a tick budget. A "4% floor" is explicitly
void when `W_max < 4%`: a fine-grained pool cannot hold that band, and widening
past `W_max` is what fails the open.

Stated in the skill, in the `lp_slot_operator` strategy that copies it, and in
AGENT.md so the root summary no longer reads percent-first.
@greptile-apps

greptile-apps Bot commented Sep 22, 2026

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

The PR appears safe to merge; both previous findings are resolved and no new actionable issue was introduced by the latest changes.

Summary

This PR replaces a flat percentage-first LP range cap with pool-specific limits derived from bin_step or tick_spacing.

  • Documents conservative 68-bin and 119-spacing cap tables with formulas for off-table granularities.
  • Makes the venue granularity limit bind even when it falls below the usual 4% volatility floor.
  • Updates the latest revision to preserve BUY, SELL, and RANGE placement semantics while clamping.
  • Adds sufficient headroom to the rounded Orca/Raydium table values.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Read pool info] --> B{Venue}
    B -->|Meteora| C[Derive W_max from 68 bins]
    B -->|Orca or Raydium| D[Derive W_max from 119 spacings]
    C --> E[Derive provisional volatility range]
    D --> E
    E --> F{Range exceeds logarithmic cap?}
    F -->|No| G[Keep bounds]
    F -->|Yes| H[Shrink while preserving side semantics]
    H --> I[BUY below P / SELL above P / RANGE brackets P]
    G --> J[Open position]
    I --> J
Loading

Reviews (2) · Last reviewed commit: "Correct the Orca/Raydium ceiling note th..."

Comment thread agents/solana_dex_lp_expert/skills/lp_range_config/SKILL.md Outdated
Comment thread agents/solana_dex_lp_expert/skills/lp_range_config/SKILL.md Outdated
…et the clamp keep a one-sided band on its side of P

The table was computed AT 120 spacings, so rounding alone pushed 6 of its 8 entries over the cap (tick_spacing=8 at 4.80% is 120.098 spacings) — the very over-cap open this change exists to prevent. Values are now computed at 119 spacings, one unit under the cap like Meteora's 68-of-69, and the headroom is stated so a reader cannot round the last decimal back onto the cap; the off-table formula takes 119 too.

The clamp step also instructed the caller to keep P bracketed, which contradicts the one-sided BUY/SELL placement the table above defines (both bounds below P, or both above). It now preserves the band's side instead of forcing P inside it, so a valid one-sided range is neither widened across P nor skipped.

Adjacent boundary fixed while there: the 4%-floor note claimed Orca tick_spacing <= 8 falls under 4%, but W_max at 8 is 4.756% — the boundary is <= 4 (2.379%).
The table was recomputed one spacing under the cap (119, not 120), so the
"round the last decimal up and the clamp lands back on the cap" warning no
longer holds — the printed values already carry a spacing of headroom, and
5.943/9.491 are themselves rounded up from the 119-spacing figure. State
what the numbers are (ceilings at 119, rounded to four significant figures)
instead of a rounding rule that the table contradicts.
@lgrawet

lgrawet commented Sep 22, 2026

Copy link
Copy Markdown
Author

Note for whoever merges: this PR and #252 are two halves of the same fix.
This one makes the width clamp side-preserving, but the GUARDRAIL line just
above still reads "always verify lower < current_price < upper" — it still
demands a bracketing range. #252 is what turns that line into the per-side
check. Landing either alone leaves strategy.md self-contradictory.
Intended order: #251 first, then rebase #252 onto it — they touch the same
clamp paragraph.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant