● Solana · grid / mean-reversion

Build a Solana trading bot you attach to any token.

Point it at a mint. It buys low and sells high inside a rolling price window, banks profit on the way up, and runs unattended. Strong defaults out of the box — dozens of knobs when you want them.

Read this first: a grid bot wins in chop and ranges and lags a straight vertical pump (it keeps selling into strength). It is a market-making strategy, not a moonshot. Only ever attach it to a mint-renounced token, and fund it with money you can afford to lose entirely.

Live proof

The same bot, trading real money right now

These are live numbers from CyberLeek — one autonomous instance of exactly this bot on a public Solana token. They refresh every few minutes and move with the market. Not a backtest, not a projection.

Return vs. buy-and-holdhow much more the bot made than simply holding the same bag, since the tracked baseline
Realized profitbooked from actual on-chain sells — not paper gains
Sells in profit

Live from cyberleek.rhchain.network. Shown straight: this stretch has been chop-and-recovery, where a grid beats holding — in a straight vertical pump the same bot would lag holding, and this number can go negative. That is the strategy shown honestly, not a cherry-pick.

What it is

One small loop, running forever

The bot is token-agnostic: the same engine trades any SPL token you give it a mint for. It holds a rolling window of recent prices, works out where the current price sits in that window, and does the boring, profitable thing — accumulate low, distribute high, keep a fenced moonbag, and ratchet realized profit off the table.

Non-custodial

Your keys, your wallet

It signs from a burner wallet you control. Nobody deposits into it. No accounts, no custody.

Attachable

Any mint

Set one field — the token mint — and the same decision engine trades it. Run several tokens from one wallet with allocation caps.

Cost-aware

Never books a loss

A cost-basis guard means a sell can’t fire below what the bag cost. Trades only clear when the move beats round-trip fees.

Unattended

Ratchets profit

When total value crosses a trigger, it moves SOL to a separate profit wallet and keeps trading the rest.

How it works

Read → decide → swap → remember

Every cycle (~60s) the bot runs the same four steps. Nothing about it is clever; the edge is discipline and doing it consistently without emotion.

01 · READ

Price

Deepest priced pool from DexScreener / Jupiter, plus optional on-chain vault math for a true 1-second price.

02 · DECIDE

Position in range

Where does price sit in the rolling window? Low → buy. High → sell. Dead chop → hold.

03 · SWAP

Jupiter

Route the buy or sell through Jupiter with a slippage bound. One swap per cycle, max.

04 · REMEMBER

State

Persist window, cost basis, last-sell price, realized P&L, skim total. Survives restarts.

↻ repeat every cooldown window — arm it once and walk away

Quickstart

Five steps to armed

  1. Fund a fresh burner wallet.

    Generate a new keypair used only for this bot. Put in SOL you can lose entirely — this is an all-or-nothing wallet, not your savings.

  2. Pick a mint-renounced token.

    Verify mintAuthority = null (and ideally freezeAuthority = null). A live mint authority means the dev can print supply and rug you — see Safety.

  3. Paste the strong defaults.

    Drop the default config in, set mint, wallet and skim_wallet. Leave everything else alone until you have a reason.

  4. Run it disarmed first.

    Let it print its decisions (buy/sell/hold + reason) for a while with armed:false. Confirm the calls look sane on your token before it spends a cent.

  5. Arm it.

    Set armed:true. It trades on its own cadence from here. Watch the first few round-trips, then let it work.

Configuration

Strong defaults

These are battle-tested balanced defaults — a moderate window, room to accumulate, a fenced moonbag, and a profit ratchet. Copy this, set the three YOUR_… fields, and you have a working bot.

config.json — balanced defaults
# the only three you MUST set: mint, wallet, skim_wallet
{
  "mint":            "YOUR_TOKEN_MINT_ADDRESS",
  "circ_supply":     null,          # optional, for market-cap display
  "wallet":          "YOUR_BURNER_WALLET_PUBKEY",
  "skim_wallet":     "YOUR_PROFIT_WALLET_PUBKEY",

  "window_n":        40,            # rolling price window (cycles)
  "warmup_n":        8,             # samples before it trades
  "buy_zone":        0.40,          # buy in the low 40% of the window
  "sell_zone":       0.60,          # sell in the high 40%
  "confirm_tick":    0.01,          # wait for a 1% reversal off the extreme
  "round_trip_margin": 0.04,        # sell must clear the rebuy floor by 4%
  "min_spread":      0.02,          # ignore windows tighter than 2% (chop)
  "reserve_frac":    0.20,          # keep 20% of value in SOL as dry powder
  "half_kelly":      0.5,           # max fraction of the active side per trade
  "moonbag_frac":    0.15,          # never sell below 15% of peak bag
  "trend_tilt":      0.0,           # 0 = pure mean reversion; up = ride trends
  "vol_size":        true,          # size up when volatility is higher
  "rebuy_below_sell": true,         # never rebuy back above your own sell
  "rebuy_lockout_s": 14400,         # ...for 4h, then the guard releases
  "sol_alloc_frac":  1.0,           # share of wallet SOL this token may spend

  "cooldown_s":      45,            # min seconds between trades
  "slippage_bps":    150,           # 1.5% max slippage
  "sol_fee_reserve": 0.02,          # never spend SOL below this (gas)
  "min_trade_sol":   0.01,          # no dust trades (fee drag)
  "min_trade_usd":   3.0,

  "skim_trigger_usd": 1000.0,        # when total value crosses this...
  "skim_amount_usd": 500.0,         # ...bank this much SOL to skim_wallet
  "breakdown_mcap":  null,          # optional hard stop; null = no loss limit
  "armed":          false          # flip to true when you're ready
}

Everything below skim_wallet has a sane default — you can delete any line you don’t override and the engine fills it in.

Reference

Every knob, explained

The whole strategy is these parameters. Two dials matter most: the window (how far back it looks) and the zones (how eagerly it buys and sells). The rest protect you from fees, dust, and your own past trades.

ParamWhat it doesDefaultTune up / downSafe range
window_nLength of the rolling price window. The whole “range” is derived from it.40 smoother, longer swings, fewer trades. reacts to micro-moves, trades more (and churns more).20–120
buy_zoneBuy when price sits at or below this position in the window (0 = the low).0.40 buys more eagerly / higher. waits for deeper dips.0.25–0.45
sell_zoneSell when price is at or above this position (1 = the high). The buy→sell gap is the “no-trade” deadband.0.60 sells sooner, more trades. holds for the top, rides more.0.55–0.90
confirm_tickRequire a reversal this far off the extreme before acting (anti-knife-catch).0.01 stronger confirmation, fewer false entries. faster, twitchier.0.005–0.02
round_trip_marginA sell must clear the rebuy floor (window low) by this much — guarantees room to buy back lower.0.04 only sells with fat margin. sells closer to the floor.0.015–0.06
min_spreadSkip windows narrower than this — dead chop where the move can’t beat fees.0.02 only trade real volatility. trade tighter ranges (riskier vs cost).0.02–0.05
reserve_fracKeep at least this share of tradeable value in SOL as dry powder. Caps buying, never selling.0.20 more powder for dips, slower accumulation. deploys harder, can get stuck long.0.15–0.35
half_kellyMax fraction of the active side traded per order; scales position size.0.5 bigger, bolder slices. smaller, steadier.0.4–0.9
moonbag_fracFenced share of the peak token bag that is never sold — your free ride if it moons.0.15 hold more for the moon, less to trade. scalp everything.0.0–0.25
trend_tiltBias the zones with the trend: raise buy_zone in an uptrend so it holds/rides instead of selling into strength.0.0 rides pumps (less mean-reversion). 0 = pure buy-low/sell-high.0.0–0.5
vol_sizeScale trade size up when recent volatility is high.trueTurn off for uniform sizing.true/false
rebuy_below_sellThe anti-leak guard: after a sell, refuse to buy back above that sell price (minus round_trip_margin). Dips still buy.trueTurn off only for a fast two-way scalper that intentionally re-enters quickly.true/false
rebuy_lockout_sHow long that guard holds before releasing (so a genuine breakout isn’t blocked forever).14400 stricter. re-enters sooner.1h–8h
sol_alloc_fracCap this token’s spend to a fraction of the shared wallet’s SOL — run several tokens from one wallet.1.0Split across tokens so they sum to ≤ 1.0.0.1–1.0
cooldown_sMinimum seconds between any two trades.45 calmer, fewer trades. more aggressive.30–180
slippage_bpsMax slippage tolerated on a swap (150 = 1.5%).150Raise for illiquid tokens; keep tight where you can.50–300
sol_fee_reserveNever let wallet SOL drop below this — always keep gas.0.02Raise if you fire many trades per hour.0.01–0.05
min_trade_sol / min_trade_usdFloor on trade size so gas doesn’t eat micro-trades.0.01 / 3 on tiny wallets so each round-trip clears gas.$3–$10
skim_trigger_usd / skim_amount_usdProfit ratchet: when total value crosses the trigger, move this much SOL to the profit wallet.1000 / 500Lower the trigger to bank sooner.your call
breakdown_mcapOptional hard stop: dump if market cap falls below this. Off by default.nullSet a number to add a stop-loss (see Safety).null / mcap

Strategy presets

Three real patterns

Same engine, three personalities. Run two side-by-side on the same token from different wallets and let the market tell you which fits it.

Conservative

Accumulator

Wide window, sells only near the top, rides trends. Trades rarely, grows the stack.
overrides
{
  "window_n": 60,
  "buy_zone": 0.35,
  "sell_zone": 0.85,
  "trend_tilt": 0.3,
  "moonbag_frac": 0.10,
  "min_spread": 0.04,
  "cooldown_s": 120,
  "rebuy_below_sell": true
}

Pick when: the token is trending up or you believe in it long-term and want to lag hold as little as possible while still harvesting swings.

Balanced

The defaults

The config above, unchanged. A good place to start on almost any liquid, ranging token.

Use the strong defaults as-is. Moderate window, moderate zones, 15% moonbag, profit ratchet on. Watch a day of decisions, then nudge one knob at a time.

Aggressive

Sideways scalp

Short window, tight bands, no moonbag, ignores the pump. Collects chop — many small, cost-clearing round-trips.
overrides
{
  "window_n": 20,
  "buy_zone": 0.44,
  "sell_zone": 0.56,
  "trend_tilt": 0.0,
  "moonbag_frac": 0.0,
  "half_kelly": 0.85,
  "cooldown_s": 60,
  "min_spread": 0.022,
  "round_trip_margin": 0.015,
  "min_trade_usd": 6,
  "rebuy_below_sell": false
}
⚠ Make it clear its costs
Tight bands mean small gross gains. Each round-trip must beat ~1% LP+slippage plus gas — that’s why min_trade_usd is raised and min_spread stays ≥ 2%. On a thin wallet, bump the trade floor higher, not lower.

Pick when: the token is ranging sideways with steady volatility and you want to farm the chop rather than wait for a top. It will underperform in a straight pump — that’s the trade-off.

Safety

How to not get wrecked

☠ Only attach to mint-renounced tokens
If a token’s mint authority is still live, the developer can print unlimited new supply and drain every pool — no strategy survives that. Check it before you fund anything:
check the mint — mintAuthority must be null
curl -s https://api.mainnet-beta.solana.com -X POST \
  -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"getAccountInfo",
       "params":["<MINT>",{"encoding":"jsonParsed"}]}' \
  | python3 -c 'import sys,json; i=json.load(sys.stdin)["result"]["value"]["data"]["parsed"]["info"]; \
print("mintAuthority:", i["mintAuthority"], " freezeAuthority:", i["freezeAuthority"])'

# mintAuthority: None   freezeAuthority: None   <- SAFE (renounced)
# anything else -> do NOT attach the bot
Rule 1

All-or-nothing wallet

Fund a dedicated burner with only what you’re willing to lose completely. Never your main wallet, never rent money.

Rule 2

Clear your costs

Every round-trip pays ~1% LP + slippage plus a bit of gas. If the captured spread doesn’t beat that, you bleed. Keep min_spread and trade floors honest.

Rule 3

The cost-basis guard

A sell can never fire below the bag’s average cost. It would rather hold underwater than lock a loss — which is why there’s no panic-selling.

Rule 4

Honest numbers

If you show performance publicly, report realized P&L from actual fills. Don’t credit unrealized or double-count skimmed profit.

On the missing stop-loss
By default breakdown_mcap is nullno stop-loss. For a token you believe in, a stop just sells the bottom of every dip the grid is designed to buy. For a token you don’t, set breakdown_mcap to a floor and it will bail below it. Know which one you’re running.

For AI agents

Scaffold it from this spec

If you’re an AI building this bot, implement the loop below verbatim. It is the exact decision logic behind the defaults above — no hidden magic.

decision engine — pseudocode
# run every cooldown_s seconds, one swap per cycle max
window   = last window_n prices        # need >= warmup_n first
r_lo, r_hi = min(window), max(window)
pos      = (price - r_lo) / (r_hi - r_lo)      # 0 = low, 1 = high
spread   = (r_hi - r_lo) / price
if spread < min_spread: return HOLD            # dead chop

# --- SELL: high in range, confirmed, profitable, clear of the floor ---
if pos >= sell_zone
   and price <= r_hi * (1 - confirm_tick)       # ticked down off the high
   and price >= r_lo * (1 + round_trip_margin)  # above the rebuy floor
   and price >= avg_cost * (1 + sell_margin):   # never sell below cost
      size = half_kelly * (0.4 + 0.6*pos) * vol_boost
      sell min(tradeable, bag*size)             # tradeable excludes moonbag
      record last_sell_price = price; return

# --- BUY: low in range, ticked up, dry powder, not above our own sell ---
spendable = wallet_sol - sol_fee_reserve
keep reserve_frac of total value in SOL         # -> spend_room
blocked = rebuy_below_sell and last_sell_price
          and now - last_sell_ts < rebuy_lockout_s
          and price > last_sell_price*(1 - round_trip_margin)
if pos <= buy_zone
   and price >= r_lo * (1 + confirm_tick)        # ticked up off the low
   and spend_room > 0 and not blocked:
      size = half_kelly * (0.4 + 0.6*(1-pos)) * vol_boost
      buy  min(spendable*size, spend_room) * sol_alloc_frac
      return

return HOLD

# after any cycle: if sol_bal*price_val + bag*price >= skim_trigger_usd:
#   move skim_amount_usd of SOL -> skim_wallet (bank profit, keep trading)
config schema (types)
mint: string(required)   circ_supply: number|null   wallet: pubkey   skim_wallet: pubkey
window_n:int  warmup_n:int  buy_zone:0..1  sell_zone:0..1  confirm_tick:0..1
round_trip_margin:0..1  min_spread:0..1  reserve_frac:0..1  half_kelly:0..1
moonbag_frac:0..1  trend_tilt:0..1  vol_size:bool  rebuy_below_sell:bool
rebuy_lockout_s:int  sol_alloc_frac:0..1  cooldown_s:int  slippage_bps:int
sol_fee_reserve:number  min_trade_sol:number  min_trade_usd:number
skim_trigger_usd:number  skim_amount_usd:number  breakdown_mcap:number|null  armed:bool

Dependencies to wire: a price source (DexScreener or Jupiter quote for the deepest priced pool), Jupiter for swaps, a Solana RPC for balances and the mint-authority safety read, and a small JSON state file per token (window, avg_cost, last_sell_price, realized_pnl, skim_total, peak_token).

FAQ

Straight answers

Which tokens should I attach it to?
Mint-renounced tokens with real liquidity that trade sideways or in ranges. Avoid anything with a live mint/freeze authority, near-zero liquidity, or a vertical one-way chart — grids need two-sided movement to work.
How much money?
Only what you can lose entirely. The bot is a strategy, not a guarantee; the token can still go to zero. Start small, prove the behavior on your token, then scale if it earns it.
Why is it “losing” to just holding during a pump?
That’s expected. A grid sells into strength, so in a straight vertical move it books gains but ends with fewer tokens than a holder. It makes that back — and beats holding — in the chop and pullbacks that follow. If you only expect straight up, hold; don’t grid.
Can it get rugged?
If you attach it to a token whose dev can mint or freeze, yes — instantly. That’s why the very first step is checking mintAuthority. The bot can’t protect you from a token designed to rug.
Who holds the funds?
You do. It signs from your burner wallet and swaps through Jupiter. There’s no deposit address, no custodian, no account. If the machine dies, your keys and coins are untouched.
Do I have to babysit it?
No — that’s the point. Arm it and it trades on its cadence, banks profit at the skim trigger, and survives restarts from its state file. Check in when you feel like it.