> ## Documentation Index
> Fetch the complete documentation index at: https://docs.picon.finance/llms.txt
> Use this file to discover all available pages before exploring further.

# Liquidity-management bots

> Patterns for automated LP tooling: rebalancing, fee harvesting, and shape strategies

Automated liquidity management — rebalancing a position as price moves, harvesting fees on a
schedule, running a "curve" or "bid-ask" strategy on a user's behalf — is a full-SDK
integration: you're using [`@picon-finance/dlmm-sdk`](/sdk/quickstart) the same way an
interactive app would, just driven by a scheduler instead of a UI.

## Watching for rebalance triggers

Subscribe to `SwapEvent` scoped to the pools you manage positions in, and compare
`postBinId` against your tracked positions' `[lowerBinId, upperBinId]` ranges — this tells you
the moment the active bin exits (or approaches the edge of) a managed range, without polling:

```ts theme={null}
const unsubscribe = await events.onEvent(rpcSubscriptions, (event) => {
  if (event.name !== "SwapEvent") return;
  if (event.data.pool !== targetPoolAddress) return;

  const outOfRange = event.data.postBinId < position.data.lowerBinId
    || event.data.postBinId > position.data.upperBinId;
  if (outOfRange) triggerRebalance(position);
}, { address: targetPoolAddress });
```

A rebalance is just a `withdraw` followed by a fresh `openPosition` + `depositByWeight` at a
new range — there's no dedicated "rebalance" instruction, since the underlying operations are
already permissionless and composable.

## Harvesting fees on a schedule

`position.getInfo()` makes exactly one RPC round trip and returns `netFeeX`/`netFeeY` — cheap
enough to poll across a managed portfolio to decide when a claim is worth the transaction cost:

```ts theme={null}
const info = await position.getInfo();
const worthClaiming = info.netFeeX > threshold || info.netFeeY > threshold;
```

For many positions at once, `Position.claimAllFees()` batches efficiently — see
[SDK → Positions](/sdk/positions#claiming-across-many-positions).

## Implementing shape strategies

Since Spot/Curve/Bid-Ask aren't SDK concepts (see
[Positions and liquidity](/concepts/positions-and-liquidity#depositing-by-weight)), a
shape-strategy bot owns this logic itself. The pattern is straightforward — generate a weight
array as a pure function of range width and active-bin position, then pass it straight to
`depositByWeight`:

```ts theme={null}
function curveWeights(binCount: number, activeIndex: number): number[] {
  const maxWeight = 65_534; // u16 range
  const maxDistance = Math.max(1, activeIndex, binCount - 1 - activeIndex);
  return Array.from({ length: binCount }, (_, i) => {
    const distance = Math.abs(i - activeIndex);
    return Math.max(1, Math.round(maxWeight * (1 - distance / maxDistance)));
  });
}
```

Recompute the weight array on every rebalance (the active bin's position within the range
changes each time), not once at position-open time.

## Choosing a distribution mode for automated deposits

For a bot depositing on a user's behalf without per-deposit user input, `Balanced` is usually
the safer default — it won't silently overweight one side of a volatile active bin the way
`UnbalancedX`/`UnbalancedY` can. Be aware `Balanced` can leave part of a side's requested amount
undeposited if the two sides' weight demand is asymmetric (see
[Positions and liquidity](/concepts/positions-and-liquidity#distribution-modes)) — reconcile
your bot's accounting against what was *actually* charged (readable from the resulting
`DepositEvent`), not just what was requested.
