My App
Buy Bot

Message layout

Every buy post — the default layout and any custom body — is built from `{PLACEHOLDER}` tokens inside header, body and row runs. Twenty tokens resolve to…

Message layout

Every buy post — the default layout and any custom body — is built from {PLACEHOLDER} tokens inside header, body and row runs. Twenty tokens resolve to text; eleven of them can also serve as a run's own link target.

Text placeholders

TokenWhat it rendersNotes
{AMOUNT}Native amount spent, quantity-formatted.Always renders, even for a zero-value buy — never empty, so it can't trigger a drop by itself.
{NATIVE}Native token symbol of the chain.Identity placeholder (IDENTITY_PH) — never decides a drop.
{USD}The buy amount in USD, 2 decimal places.Always renders ($0.00 at minimum) — never empty.
{TOKENS}Tokens received, quantity-formatted.Always renders — never empty.
{TOKEN}Token symbol.Identity placeholder — never decides a drop. See Case matters, below.
{token}Token name — the long name.Identity placeholder — never decides a drop. See Case matters, below.
{PRICE}Formatted USD price per token.Always renders — a non-positive price literally renders $?, never empty.
{MCAP}Market cap in USD, 0 decimal places.Always renders ($0 at minimum) — never empty.
{WALLET}Shortened buyer wallet — first 6 characters + last 4, past 12 characters.Linked to the address explorer when walletLinkOn is on. Empty only if the buy carries no wallet address at all — can drop its line.
{POSITION}New!, or a +-prefixed percentage change (1 decimal place).Empty only when the pre-buy balance couldn't be read — the one case where it can drop its line.
{EMOJIS}The size row — the size emoji repeated N times. See Size-emoji scaling, below.Identity placeholder — never decides a drop. Raw HTML, never escaped.
{TX}The literal word Tx, linked to the transaction explorer.Empty when txLinkOn is off or no tx explorer base resolves — can drop its line.
{CHART}The configured chart label, linked to the resolved chart URL.Empty when no chart resolves — can drop its line.
{CA}The contract address — the config's own, else the market's base mint.Empty only if neither one resolves (a live buy bot always has a contract address) — can drop its line.
{DEX}The DEX name, hyphens replaced with spaces, Title Cased.Empty when the market carries no DEX name — can drop its line.
{HOLDS}The buyer's token balance after this buy.Empty when the pre-buy balance couldn't be read — can drop its line.
{LIQ}Liquidity in USD, 0 decimal places.Empty when ≤ 0 — can drop its line.
{VOL24}24-hour volume in USD, 0 decimal places.Empty when ≤ 0 — can drop its line.
{BUYS24}24-hour buy count, comma-grouped.Empty when 0 — can drop its line.
{HOLDERS}Holder count, comma-grouped.Empty unless a positive integer — can drop its line.

Note

Quantity fields — {AMOUNT}, {TOKENS}, {HOLDS} — share one formatter (_fmt_qty): comma-grouped with 0 decimals at 1,000 or over; 2 decimals with trailing zeros stripped from 1 up to 1,000; 4 decimals with trailing zeros stripped below 1.

Note

{TOKEN}, {token}, {NATIVE} and {EMOJIS} are the four identity placeholders (IDENTITY_PH). The code's own comment on that set: "always filled; never decide a line drop."

Case matters: {token} vs {TOKEN}

Note

Placeholder case is meaningful. {TOKEN} (uppercase) renders the token's symbol. {token} (lowercase) renders the token's name — the long name. token/TOKEN is the only placeholder that exists in both cases; every other placeholder is uppercase-only.

Case rule, rendered

InputOutput
Template line{TOKENS} {TOKEN} vs {token}
Rendered1,000 NOT vs Notcoin

URL-slot tokens

11 of the 20 placeholders can also fill a run's own link target directly.

TokenLinks toWhen unset
{TX}The transaction, on the chain's tx explorer.Renders empty — no link, no text — when txLinkOn is off or no tx explorer base resolves.
{CHART}The resolved chart URL for the configured chartProvider.Empty when no chart resolves.
{WALLET}The buyer wallet, on the chain's address explorer.Text still renders; just unlinked, when walletLinkOn is off.
{WEBSITE}The Website link slot.Plain text, not a dead link.
{TWITTER}The X link slot (/buybotx, /buybottwitter). Where the bot auto-labels this slot — the default layout's tail link — the label is X, never "Twitter" (SITE_LINK_LABEL).Plain text, not a dead link.
{TELEGRAM}The Telegram link slot.Plain text, not a dead link.
{DISCORD}The Discord link slot.Plain text, not a dead link.
{DOCS}The Docs link slot.Plain text, not a dead link.
{MEDIUM}The Medium link slot.Plain text, not a dead link.
{REDDIT}The Reddit link slot.Plain text, not a dead link.
{GITHUB}The GitHub link slot.Plain text, not a dead link.

Note

An unset site-link slot renders as plain text, never a dead link — the run keeps its label, it just isn't wrapped in a link.

The default layout (no custom body)

With no custom body set, the bot renders a fixed structure instead of running the line-drop rule at all: a header, the emoji row, a blank line, six body rows in a fixed order, then a blank line and a tail of links.

  1. Header — the owner's headerParts if set, else <Name> Buy!, the name linked to the chart when one resolves.
  2. The emoji row ({EMOJIS}).
  3. A blank line.
  4. Six rows, in this fixed order (ROW_KEYS): spent, tokens, price, marketCap, wallet, position. position is skipped only when its value is empty (the pre-buy balance couldn't be read); any other row that renders empty is skipped the same way.
  5. A blank line, then a tail of links on one line, joined with |: Tx, Chart, the owner's extraLinks (max 4), then whichever site-link slots are set.

Default row templates, each with its default icon

SettingValue
spent 💰{AMOUNT} {NATIVE} ({USD})
tokens 🪙{TOKENS} {TOKEN}
price 🏷Price: {PRICE}
marketCap 🔼Mkt Cap: {MCAP}
wallet 🔍{WALLET}
position ⬆️Position: {POSITION}

Default tokens row, rendered

InputOutput
Template (tokens row, default icon)🪙 {TOKENS} {TOKEN}
Rendered🪙 1,000 NOT

Bold markup omitted above; on Telegram “1,000 NOT” renders bold.

The line-drop rule

Applies only once the buy bot has a custom body set. The default layout above is never subject to it.

  1. The body is split into lines on the newlines inside its text runs (_split_lines) — that is the unit the rule works on.
  2. For each line, its placeholders are collected, excluding the four identity placeholders.
  3. A line is dropped when it has at least one non-identity placeholder, every one of them renders empty, and the rendered line contains no <a anchor.
  4. A blank line directly after a dropped line is swallowed too, so a drop never leaves a double gap.

Line-drop rule, rendered

InputOutput
TemplateHolders: {HOLDERS} Buy on {TOKEN}!
RenderedBuy on NOT!

{HOLDERS} has no value on this market, so the whole first line — including its literal Holders: text — is dropped. {TOKEN} is an identity placeholder, so the second line is never a drop candidate.

Note

Only 10 of the 20 placeholders can ever render empty in practice: {POSITION}, {TX}, {CHART}, {CA}, {DEX}, {HOLDS}, {LIQ}, {VOL24}, {BUYS24}, {HOLDERS}. The other six non-identity placeholders — {AMOUNT}, {USD}, {TOKENS}, {PRICE}, {MCAP}, {WALLET} — are built from formatters that always return text, so a line built only from one of those six is never dropped.

Size-emoji scaling

Size row (buybot_helper.py)

n = max(1, min(maxEmojis, ceil(usd / usdPerEmoji)))

n is how many times the size emoji (sizeEmoji, falling back to 🟢) repeats inside {EMOJIS}. usdPerEmoji == 0 forces n = 1.

SettingValue
usdPerEmojiUSD cost of one size-row emoji. Clamped 0.01–1e9.
maxEmojisCaps the row length. Clamped 1–80, default 50.

The dashboard's "Emojis per $10" field writes usdPerEmoji = 10 ÷ n for whatever number the owner enters there.

Caption fitting

Note

A 50-emoji size row costs 100 units to Telegram, not the length of the raw tg-emoji markup.

SettingValue
With media (photo, GIF or video attached)1024 units
Text-only4096 units

Lines that don't fit are dropped whole from the end, never cut inside a tag. If even the first line doesn't fit on its own, it is truncated character by character instead, surrogate-pair aware.

On this page