Regolancer
lnd channel rebalancer written in Go
Install / Use
/learn @rkfg/RegolancerREADME
Intro
Why even write another rebalancer? Usually, the only motivation is that the existing software doesn't satisfy the developer. There may be different reasons why improving the existing programs isn't something the dev wants. Maybe the language is the problem or architecture. For me there were many reasons including these. Two most advanced rebalancers for lnd are rebalance-lnd (Python) and bos (JS). However, each has something the other one lacks, both have runtime requirements and both are slow. I decided to fix these issues by rewriting the things I liked in Go instead so it can be easily compiled and used anywhere. I also made the output pretty, close to the design of accumulator's fork of rebalance-lnd.

Features
- automatically pick source and target channel by local/remote liquidity ratio
- retry indefinitely until it succeeds or 6 hours pass (by default)
- payments time out after 5 minutes (by default) so if something's stuck the process will continue shortly
- timeouts can be customized
- JSON/TOML config file to set some defaults you prefer
- optional route probing using binary search to rebalance a smaller amount
- optional rapid rebalancing using the same route for further rebalances unitl route is depleted in case a rebalance succeeds
- data caching to speed up alias resolution, quickly skip failing channel pairs etc.
- storing/loading cached nodes information to disk to "warm up" much faster next time you launch the program
- sensible node capacity formatting according to Bitcoin design guidelines (easy to tell how many full coins there are)
- automatic max fee calculation from the target channel policy and preferred economy fee ratio (the amount spent on rebalance to the expected income from this channel)
- excluding your channels from consideration
- excluding any nodes from routing through (if they're known to be slow or constantly failing to route anything)
- using just one source and/or target channel (by default all imbalanced channels are considered and pairs are chosen randomly)
- calculate the rebalance amount automatically from current and desired balance percent
- safety precautions that prevent balances going beyond 50% of channel capacity, can be turned off explicitly if that's what you want
- saving successful rebalance parameters into a CSV file for further profit analysis with any external tools
Installation
You need to have Go SDK installed, then simply run go install github.com/rkfg/regolancer@latest and by default it will download, compile and
build the binary in ~/go/bin/regolancer. To crosscompile for other platforms
use GOARCH and GOOS env vars to choose the target architecture and OS. For
RPi run it as GOARCH=arm64 go install github.com/rkfg/regolancer@latest if you
run a 64 bit system (and you should!). You'll find the binaries in
~/go/bin/linux_arm64. For 32 bit use GOARCH=arm, the binary will be located
in ~/go/bin/linux_arm.
Parameters
Config:
-f, --config config file path
Node Connection:
-c, --connect connect to lnd using host:port
-t, --tlscert path to tls.cert to connect
--macaroon-dir path to the macaroon directory
--macaroon-filename macaroon filename
-n, --network bitcoin network to use
Common:
--pfrom channels with less than this inbound liquidity percentage will be considered as source channels
--pto channels with less than this outbound liquidity percentage will be considered as target channels
-p, --perc use this value as both pfrom and pto from above
-a, --amount amount to rebalance
--rel-amount-to calculate amount as the target channel capacity fraction (for example, 0.2 means you want to achieve at most 20% target channel local balance)
--rel-amount-from calculate amount as the source channel capacity fraction (for example, 0.2 means you want to achieve at most 20% source channel remote balance)
-b, --probe-steps if the payment fails at the last hop try to probe lower amount using this many steps
--allow-rapid-rebalance if a rebalance succeeds the route will be used for further rebalances until criteria for channels is not satifsied
--min-amount if probing is enabled this will be the minimum amount to try
-i, --exclude-channel-in (DEPRECATED) don't use this channel as incoming (can be specified multiple times)
-o, --exclude-channel-out (DEPRECATED) don't use this channel as outgoing (can be specified multiple times)
--exclude-from don't use this node or channel as source (can be specified multiple times)
--exclude-to don't use this node or channel as target (can be specified multiple times)
-e, --exclude-channel (DEPRECATED) don't use this channel at all (can be specified multiple times)
-d, --exclude-node (DEPRECATED) don't use this node for routing (can be specified multiple times)
--exclude don't use this node or your channel for routing (can be specified multiple times)
--exclude-channel-age don't use channels opened less than this number of blocks ago
--to try only this channel or node as target (should satisfy other constraints too; can be specified multiple times)
--from try only this channel or node as source (should satisfy other constraints too; can be specified multiple times)
--fail-tolerance a payment that differs from the prior attempt by this ppm will be cancelled
--allow-unbalance-from (DEPRECATED) let the source channel go below 50% local liquidity, use if you want to drain a channel; you should also set --pfrom to >50
--allow-unbalance-to (DEPRECATED) let the target channel go above 50% local liquidity, use if you want to refill a channel; you should also set --pto to >50
-r, --econ-ratio economical ratio for fee limit calculation as a multiple of target channel fee (for example, 0.5 means you want to pay at max half the fee you might
earn for routing out of the target channel)
--econ-ratio-max-ppm limits the max fee ppm for a rebalance when using econ ratio
-F, --fee-limit-ppm don't consider the target channel fee and use this max fee ppm instead (can rebalance at a loss, be careful)
-l, --lost-profit also consider the source channel fee when looking for profitable routes so that route_fee < target_fee * econ_ratio - source_fee
Node Cache:
--node-cache-filename save and load other nodes information to this file, improves cold start performance
--node-cache-lifetime nodes with last update older than this time (in minutes) will be removed from cache after loading it
--node-cache-info show red and cyan 'x' characters in routes to indicate node cache misses and hits respectively
Timeouts:
--timeout-rebalance max rebalance session time in minutes
--timeout-attempt max attempt time in minutes
--timeout-info max general info query time (local channels, node id etc.) in seconds
--timeout-route max channel selection and route query time in seconds
Others:
-s, --stat save successful rebalance information to the specified CSV file
-v, --version show program version and exit
--info show rebalance information
-h, --help Show this help message
Look in config.json.sample or config.toml.sample for corresponding keys,
they're not exactly equivalent. If in doubt, open main.go and look at the var params struct. If defined in both config and CLI, the CLI parameters take
priority. Connect, macaroon and tls settings can be omitted if you have a
default lnd installation.
Node cache
Enable the cache by setting --node-cache-filename=/path/to/cache.dat (or
node_cache_filename config parameter), you're free to choose any path and file
name you like. It speeds up printing routes and lowers load on lnd in case you
run multiple regolancer instances. If you're not interested in technical
details, feel free to skip the following section.
How this cache works
Node cache is only used for printing routes, it contains basic node information such as alias, total capacity, number of channels, features etc. However, getting this information might be slow as every request to lnd is processed sequentially. The first few routes print noticeably slower until more nodes "around" you are queried and cached in RAM. This information shouldn't be very up-to-date (unlike the channel balances, policies etc. which are retrieved on every launch and are only cached for the run time) and nodes themselves broadcast updates not very often. It makes sense to persist this data to disk and load it on every run so that routes are printed almost instantly, and the payment is only attempted after the route is fully printed. It would be good to run a payment attempt and route print in parallel but currently the payment function can dump errors and it would interfere with the route output.
However, there's a gotcha that I learned from other users of regolancer: people run multiple instances of it in parallel, so they might terminate at different times. If all those instances use the same cache file, they will overwrite it and lose information that another instance might have stored before them, or they might start writing at the same time and corrupt it. One way to solve it is to use separate cache files
