Trade Bot Dictionary · Crypto

onchain_fees_anchor

onchain_fees_anchor is a master switch wired to the price of getting a Bitcoin transaction into the next block. Every five minutes we ask mempool.space what fee rate you'd have to pay right now to be mined immediately, in satoshis per virtual byte, and you pick a condition off it — "only when fees are above 10", "only when they're below 5". While your condition holds the bot trades; while it doesn't, the bot places no trades at all that cycle, in any market. It gates the whole bot, not just crypto markets.

Bots using it
0 (none live, none out-of-sample, none ever)
Data source
mempool.space /api/v1/fees/recommended
Refresh
Every 5 minutes (*/5 * * * *) — but see catch #3
Rows stored
1,862 readings 7 days — the rest is deleted
Backtest-replayable
No — see catch #5
Anchor module
quants/onchain_fees_anchor.py

The premise is sound and unusually easy to explain. Bitcoin blocks have a fixed amount of room in them and one arrives roughly every ten minutes. If lots of people want to transact, they bid against each other for that room, and the price of a spot goes up. So the fee rate is a live auction price for blockspace — a direct read on how much the network is actually being used, not on what anyone thinks it's worth. It moves on settlement demand rather than on quotes. Our module says that, the builder says that, and the starter bot we ship says that.

The trouble is that we set the price of "busy" three years ago and the chain has been getting steadily cheaper ever since. Every place this site suggests a number — the builder's default field value, the builder's one-click recipe, the starter bot, and the module's own docstring example — says the same thing: above 10 sat/vB. Across all 1,862 readings we hold, that condition was open 0.00% of the time. Not rarely. Never. The highest reading in the week is exactly 10, and the comparison is a strict greater-than, so even that one doesn't open it.

That is not because 10 is a silly number. Pulled from mempool.space's own free history, the typical block's 90th-percentile fee rate cleared 10 sat/vB in 15 of the last 37 months, and in December 2023 the typical month sat at 203 sat/vB — twenty times the threshold. The number was chosen for a chain that no longer exists. The last month in which a typical block's 90th-percentile fee even reached 10 was December 2024, twenty months ago. Nothing on this site tells you that.

How onchain_fees_anchor gets from mempool.space to a trade decision, how far Bitcoin's fee market has fallen below the threshold we ship, how coarse the readings we keep actually are, and how half our samples are being lost to our own backtest index The top band traces the data path. The source is mempool.space's recommended-fee endpoint at mempool dot space slash api slash v1 slash fees slash recommended — free, no key, no account, and it answered in 0.19 seconds when called live from the production server at about 23:20 UTC on the eleventh of August 2026, returning a fastest-fee of 3 satoshis per virtual byte. Our poller, predictive slash crypto underscore poller dot py, runs on a cron of star slash five, meaning every five minutes, 288 times a day. It takes only the fastestFee field. That step sits inside its own isolated try-except block, deliberately, so a mempool.space failure can never break the core coin-price polling. It writes a row into the onchain_fees table in predictive dot db, alongside a mempool transaction count that the gate never reads. That table holds 1,862 readings covering the fourth to the eleventh of August 2026, and it is pruned to seven days. The gate function in quants slash onchain underscore fees underscore anchor dot py asks whether the latest reading is above or below your chosen rate, and refuses to answer at all if that reading is more than 90 minutes old. Pass means the bot scans markets as normal; fail means the bot places no trades at all that cycle, in any market. Nothing is downstream of it: no bot on the platform uses this signal. The second band is the important one. It plots three years of Bitcoin fee rates on a logarithmic scale, month by month from August 2023 to August 2026, taken from mempool dot space's free mining blocks fee-rates endpoint. Two lines are drawn: the median month's typical block median fee rate, and the median month's typical block ninetieth-percentile fee rate. Both start high. The ninetieth-percentile line peaks in December 2023 at 203.5 satoshis per virtual byte and the median line at 136. April 2024 shows a second spike, with a single group of blocks reaching 1,636. From mid-2024 both lines fall steadily and then flatten: from December 2025 through August 2026 the ninetieth-percentile line sits flat at 3 and the median at 1. A horizontal line marks 10 satoshis per virtual byte — the number used by the builder's default, the builder's recipe, the starter bot, and the module's own docstring. The ninetieth-percentile line is above that threshold for the first seventeen months of the chart and below it for the last twenty, having last cleared it in December 2024. The eight days we actually keep are a sliver at the far right-hand edge, entirely underneath the threshold. The third band has two panels. The left panel is a histogram of all 1,862 readings we hold. The endpoint returns whole numbers only, so the entire week is spread across just ten possible values: 1 appears 584 times, 2 appears 689 times, 3 appears 373 times, 4 appears 140 times, 5 appears 50 times, 6 appears 14 times, 7 appears 7 times, 8 appears 3 times, 9 appears once and 10 appears once. Values 1, 2 and 3 together account for 88.4 percent of the week. The threshold we ship, above 10, is drawn as a line past the right-hand end of every bar, because no reading ever reached it. The right panel compares how much history exists with how much we keep: mempool dot space serves 6,425 daily fee-rate readings going back to the third of January 2009, free and keyless, which is 17.6 years; we keep 8 days, about one tenth of one percent of it. The bottom band shows one hour of the current polling schedule. Our fee poller is supposed to fire twelve times an hour, at zero, five, ten and so on. A second job, predictive dot ticker underscore index, runs every ten minutes on the even boundaries and writes to the same database for about two minutes each time. Every poll that starts on an even ten-minute boundary collides with it and loses its row to a database-is-locked error; every poll on an odd five-minute boundary survives. Over the forty-nine hours to the eleventh of August 2026 that pattern is exact: 288 rows landed on odd boundaries and zero landed on even ones. 1 · The data path source → poller → table → gate → decision. Verified live from the production server, 11 Aug 2026. mempool.space /api/v1/fees/ recommended free · no key · 0.19 s crypto_poller */5 * * * * takes one field: fastestFee onchain_fees predictive.db 1,862 rows · 7 days then deleted the gate above / below ? stale > 90 min → fails closed the whole bot trades / stands down 0 bots downstream Whole numbers only loses every even 10-min slot (band 4) 17.6 yrs exist free; we keep 8 days no hysteresis: ~21 flips/day gates every market, not just crypto 2 · Three years of Bitcoin fee rates, against the one number we ship Monthly medians from mempool.space /api/v1/mining/blocks/fee-rates/3y — free, keyless, HTTP 200. Log scale (sat/vB). 300 100 30 3 1 10 sat/vB — every setting we ship Dec 2023 — 203 sat/vB last month above: Dec 2024 flat at 3 and 1 for nine months ← the 8 days we keep Aug 2023 May 2024 Feb 2025 Nov 2025 typical block's 90th-percentile fee typical block's median fee 3 · What a week of readings actually looks like All 1,862 readings, 4–11 Aug 2026. The endpoint returns whole numbers, so the week has ten possible values — and uses three of them. 584 1 689 2 373 3 140 4 50 5 14 6 7 7 3 8 1 9 1 10 sat/vB → 1, 2 and 3 = 88.4% of the week above 10 0 of 1,862 History that is free vs history we keep mempool.space, free + keyless — 17.6 years 6,425 daily readings · back to 3 Jan 2009 what we keep 8 days — 0.12% of what is free Different series, though: that history is what blocks actually paid. Ours is what mempool.space recommends. Nobody archives that. See catch #5. 4 · One hour of the current schedule — half of it is thrown away Since 09 Aug 2026 23:00 UTC, every poll on an even ten-minute boundary loses its row to database is locked. 49 hours and counting. ticker_index */10, ~118 s each, same DB fee poll :00 :05 :10 :15 :20 :25 :30 :35 :40 :45 :50 :55 Measured over those 49 hours: 288 rows on odd boundaries, 0 rows on even ones. mempool.space has failed us once, ever; our own database has, 2,418 times.
Everything here was measured on 11 August 2026: the pipeline from the module and poller source and a live call to the endpoint, the three-year chart from mempool.space's free fee-rates history, the histogram and the polling strip from the production database. The two chart lines are monthly medians of per-block percentiles, so they smooth out intra-month spikes — April 2024 contains a single group of blocks at 1,636 sat/vB that the line does not show.

Where the data comes from

One endpoint, and it is about as simple as this gets: https://mempool.space/api/v1/fees/recommended. Free, no key, no account, no registration. Called live from our production server on 11 August 2026 it returned HTTP 200 in 0.19 seconds with this:

{"fastestFee":3,"halfHourFee":3,"hourFee":1,"economyFee":1,"minimumFee":1}

We take exactly one of those five numbers, fastestFee — mempool.space's estimate of the fee rate you'd need to pay right now to make it into the very next block. The fetcher lives in predictive/crypto_poller.py, runs on cron */5 * * * * (288 times a day), and writes a row into the onchain_fees table in predictive.db. As of this writing that table holds 1,862 readings spanning 4–11 August 2026, with a mean of 2.18 sat/vB, a minimum of 1 and a maximum of 10.

The same function makes a second, optional call to https://mempool.space/api/mempool for the number of unconfirmed transactions waiting, and stores it in the same row. That one is wrapped in its own try/except so a failure there can never cost us the headline fee. It is populated on all 1,862 rows — and the gate has never once looked at it (catch #7).

This is the last of four signals on this one poller, and the only one that doesn't ride CoinGecko. The other three — crypto_momentum_anchor, btc_dominance_anchor and stablecoin_share_anchor — share a single call to CoinGecko's /global. This one has its own fetch, its own isolated try/except and its own failure profile, so none of their coverage numbers transfer to it. Like all three, it has no bot.

A correction to our own registry

quants/signal_registry.py is the tool that resolves every signal on this site to its source. For this signal it reports the source as "undocumented". That is wrong, and in an interesting way: the anchor's docstring names mempool.space in its second sentence. The registry identifies sources by matching a module's prose against a hand-written list of seventeen vendor names — SOURCE_HINTS — and nobody ever added mempool.space to it. The comment above that list says it exists so that "if a docstring doesn't say where the data comes from, we report 'undocumented' rather than guessing", which is the right instinct; this is that instinct producing a false negative rather than a fabrication. Everything else the registry says about this signal — poller, cron, table, not replayable, 0 bots — checks out.

What it means for your bot

Mechanically it is a master switch, and it is evaluated before anything else. In quants/engine.py the check runs near the top of the cycle and, if it fails, returns an empty list — no markets are scanned, no candidates are produced, nothing is bought. It is not a filter that prefers certain markets. It is an on/off switch for the entire bot, and nothing in the config validator ties it to crypto markets. If your bot trades MLB games, this switch can still shut it down over the price of Bitcoin blockspace.

The intended use is regime selection: trade only when the chain is busy, or only when it's quiet, on the theory that on-chain congestion tracks something real about crypto activity. That theory is weakly true and badly overstated. High fees can mean a genuine surge in settlement demand — or an inscription and token-mint wave buying exactly the same blockspace for reasons unrelated to any price, or an exchange batching its withdrawals, or simply a long gap between blocks letting the backlog pile up. Our own copy says the signal "moves on real settlement demand, not price quotes." The second half of that is true. The first half is true some of the time, and there is nothing in the number that tells you which time you're in.

For crypto markets it is a defensible, noisy attention proxy that should be made to beat simpler alternatives before you trust it. For weather, sports and most politics markets there is no channel at all from Bitcoin blockspace to how the contract resolves, and any relationship you find in a week of data is an accident.

The catch

Nine of them, worst first. Every number below was measured on 11 August 2026 from the production database, the module source, or a live call to a named endpoint.

1. 🔴 Every setting we ship is the same number, and the chain hasn't reached it in twenty months

Four places on this site suggest a value, and all four say above 10 sat/vB: the builder's default field value; the builder's one-click recipe, "On-chain activity regime"; the starter bot, "On-Chain Activity Watch"; and the module's own docstring example. Measured against all 1,862 readings we hold, that condition was open 0.00% of the time. The single highest reading in the week is exactly 10, and the comparison in the anchor is val > anchor["above"] — strictly greater — so even that one reading does not open it.

The fair counterweight, and it is a real one: 10 sat/vB was a sensible, discriminating threshold when it was written. From mempool.space's free three-year history, the median month's typical block 90th-percentile fee rate cleared 10 sat/vB in 15 of 37 months, and the median fee rate in 10 of 37. December 2023 sat at 203.5. This is not a number someone invented; it is a number that stopped being reachable. The last month in which a typical block's 90th-percentile fee reached 10 was December 2024, and since December 2025 the figure has been flat at 3.

The starter bot's own blurb says "(Right now the chain is quiet, so it stands down until activity picks up.)" That is honest about the state and misleading about the timescale: "right now" has been true for twenty months, and a user reading it would reasonably expect the bot to start trading within days. The defect here is calibration and disclosure, not the idea.

2. 🔴 The feed is integers, so the whole live range is a three-value alphabet

/api/v1/fees/recommended returns whole numbers. In a busy regime that hardly matters — the difference between 180 and 181 is noise. In the regime we are actually in, it is the whole signal. Of our 1,862 readings, 88.4% are 1, 2 or 3: 584 ones, 689 twos, 373 threes. Then 140 fours, 50 fives, and single digits above that. Our poller writes round(float(fee), 3), which is decorative — there has never been anything after the decimal point to round.

The precision exists and we don't take it. The same host's /api/v1/fees/mempool-blocks endpoint — also free, also keyless, verified HTTP 200 — returns the projected next block with a floating-point medianFee. At the moment recommended reported the integer 3, mempool-blocks reported 2.3816, with a fee range starting at 2.0082. One extra request would give this signal real resolution in the only range it currently occupies.

And the number itself is vendor-defined. At the same moment, Blockstream's free Esplora estimate for next-block confirmation (blockstream.info/api/fee-estimates, also HTTP 200, keyless) read 2.306 against mempool.space's 3. A 0.694 sat/vB disagreement is nearly a whole quantisation step on a scale whose entire working range is 1 to 5. "The Bitcoin fee rate" is not one number; it is one company's estimate of one.

3. 🔴 Half of every hour's samples are currently being eaten by our own backtest index

Across the whole retained window, coverage is 81.24% — 1,862 rows against 2,292 five-minute cycles. But that average hides a regime change. Since 09 August 2026 at 23:00 UTC, for 49 consecutive hours, coverage has been exactly 50%, and not randomly: in the last 48 hours every single row landed at :05, :15, :25, :35, :45 or :55, and not one landed at :00, :10, :20, :30, :40 or :50.

The cause is one line of our own crontab. */10 * * * * predictive.ticker_index --refresh rebuilds the mps_ticker_index table — the index that made backtests 47× faster — inside the same predictive.db. Its log shows it taking 116.8 to 120.9 seconds per run across 542,000 tickers, and it fires on the even ten-minute boundaries. Every fee poll that starts on one of those boundaries collides with it and dies on sqlite3.OperationalError: database is locked; every poll on an odd boundary runs clear. The alternation in the data is exact, and there is exactly one */10 job in the crontab.

Watched directly on the production box, it behaves precisely as that predicts: the refresh that began at 23:30:00 UTC recorded itself finished at 23:31:59 — 119 seconds — and the next one was observed starting at 23:40:00 exactly, still running 94 seconds later. Our fee poll fires at :40 too.

The vendor is not the problem — we are. Lifetime in /var/log/crypto-poller.log: onchain fees step failed 2,418 times and database is locked 4,656 times, against onchain fees fetch failed — mempool.space actually failing — once. This is the eighth job written up in this dictionary to be hit by contention on the shared predictive.db.

And our own monitoring cannot see it. signal_health.py tracks this feed with a three-hour staleness threshold. A feed arriving reliably every ten minutes instead of every five is perfectly fresh and half missing, and reports green. Recency is not completeness. Not fixed here — this loop does not touch pollers or crontabs — but written up and flagged.

4. 🔴 The gate chatters, at a sampling rate that catches block luck

52.3% of consecutive five-minute polls differ from the poll before them (973 of 1,861 transitions), and 6.0% jump by 2 sat/vB or more. There is no hysteresis anywhere in the anchor: it compares the single latest reading to your threshold and returns true or false.

The consequence, measured at the only threshold in our range that discriminates at all (above 3, open 11.59% of the time): the gate changes state 167 times in eight days — 20.9 times a day, with a median run of 3 polls, about 15 minutes. At above 2 it is worse: 48.5 flips a day. A whole-bot master switch is turning on and off roughly every quarter of an hour.

Some of that is not information at all. Bitcoin blocks arrive as a Poisson process averaging ten minutes, and when one lands, the top of the mempool is cleared and the next-block recommendation can collapse in a single poll with nothing whatsoever having changed about demand. Conversely a long gap between blocks raises the estimate while nothing is happening. Sampling a ten-minute process every five minutes and thresholding it means you are partly trading block luck. finance_anchor has the same missing-hysteresis defect on the VIX; there it crossed a line 3 times in a day, here it is an order of magnitude worse.

5. 🔴 The backtester can't replay it — and doesn't know the signal exists

The string onchain appears zero times in quants/backtest.py. It is not in _SUPPORTED_ENTRY, and it is not even in the documentary _UNSUPPORTED_ENTRY list that is supposed to record which signals can't be replayed and why. Only the catch-all saves it. So a backtest that includes this gate runs without it and still returns a curve, flagging unsupported_rules. This is the third crypto signal in a row where that documentary list has turned out to be stale.

The standard excuse — "we'd need a forward-captured series we don't have retroactively" — splits. It is refuted for the concept: mempool.space serves /api/v1/mining/blocks/fee-rates/all, verified HTTP 200, free and keyless, returning 6,425 daily readings back to 3 January 2009 — seventeen and a half years, the deepest free history found for any signal in this dictionary. A "was the chain busy" regime gate could be replayed over that tomorrow.

It is upheld for this exact number. Those are realized fee-rate percentiles from blocks that were actually mined. fastestFee is a forward recommendation computed from the mempool as it stands, and nobody archives it. The two are related but not the same series: across our eight overlapping days our instantaneous readings (daily means 1.64 to 2.87) sit consistently between the realized median (0 to 3) and the realized 90th percentile (2 to 6). Close enough to reason about a regime; not close enough to claim you replayed this gate.

6. Seven days of memory, and it isn't even seven days

The poller prunes with DELETE FROM onchain_fees WHERE fetched_at < datetime('now','-7 days'). The stored timestamps are ISO-8601 (2026-08-04T00:15:02.077228+00:00) while SQLite's datetime() returns a space-separated string (2026-08-04 23:25:24). SQLite compares them as text, and 'T' sorts after ' ', so the whole of the cut-off day survives. Real retention is 191.0 hours, not 168. Harmless in itself, and the same defect appears in all three sibling crypto signals — but it means the window is 8 calendar days, not 7, and any arithmetic you do on "a week of data" is slightly off.

The real cost is the deletion itself. Seventeen and a half years of related history is free from the vendor; a year of our own actual fastestFee series would be about 105,000 rows. We generate it 288 times a day and throw it away. Not fixed — this loop does not touch pollers.

7. The congestion depth is fetched, stored, and never read

Every row carries a mempool_count — the number of unconfirmed transactions waiting. It is populated on all 1,862 rows (minimum 67,660, maximum 107,279, mean 86,387). The gate never looks at it. There is no way to configure a bot on it, and no field for it in the builder.

That is a shame, because it tells a different story from the fee. At the live check the mempool held 81,566 unconfirmed transactions occupying 41.9 million virtual bytes — about 42 blocks of backlog — while the next-block fee was 3 sat/vB. That is not congestion; it is a queue of transactions nobody will ever mine, sitting below the price of entry. In our own data the two are only loosely coupled: correlation +0.573, meaning depth explains about a third of the variance in the fee. A bot that wants "is the chain busy" is arguably better served by the number we discard than the one we gate on.

8. Configurations that validate but cannot mean anything

validate_config accepts any number from 0 to 10,000. So:

  • {"above": 5000} validates — five hundred times the highest reading of the last three years.
  • {"below": 1} validates and is 0.00% open by construction. The endpoint floors at 1 (it reported "minimumFee":1 at the live check, and none of our 1,862 readings is below 1), while the real fee market runs underneath that — Blockstream's free estimate for a 1,008-block target read 0.104 sat/vB at the same moment. The floor is an artefact of the endpoint, not of Bitcoin.
  • {"above": 10, "below": 5} validates, is unsatisfiable, and to_english renders it as "network busy — high on-chain demand" and "chain quiet — low on-chain activity", joined by "and". The same defect is written up on finance_anchor, crypto_momentum_anchor, btc_dominance_anchor and stablecoin_share_anchor. It is a platform-wide gap in the validator, not a quirk of this signal.

9. "Busy" has at least four causes and we sell one of them

A high fee rate can mean real settlement demand; or an inscription or token-mint wave buying the same blockspace for reasons unrelated to price; or an exchange batching withdrawals; or simply a slow run of blocks. Our builder copy calls this "the live read on on-chain congestion / demand" and the module calls it "a whole-network signal most bettors never pull up… it moves on real settlement demand, not price quotes." The last clause is true — it genuinely isn't a quote-derived number, which is what makes it interesting. The claim that it measures demand specifically is only sometimes right, and the gate gives you no way to tell the cases apart.

We are not going to put a number on how often each cause dominates, because we have not measured it and eight days of a quiet chain could not settle it.

The case for the defence

  • The freshness check is correctly written. It parses the stored ISO timestamp into a real Python datetime and compares real times — not the string comparison that silently defeats the same check in finance_anchor and tropical_anchor. It also fails closed on an unparseable or missing timestamp. All four crypto_poller signals get this right.
  • It has never had to fail closed. The largest gap between readings in the whole window is 35 minutes, against a 90-minute threshold. Worth noting that at the current ten-minute cadence the margin is thinner than it was designed to be, but it has not been breached.
  • The isolation design is right, and vindicated. The fee step has its own try/except so a mempool.space failure can never break the core price polling. mempool.space has failed once in the entire log. The vendor was never the risk; the design guarded the right thing anyway.
  • The ingredient is real. It is free, keyless, fast, genuinely independent of price quotes, and genuinely not something most people betting on prediction markets pull up. The premise "the fee rate tells you how contested blockspace is" is simply true. What is contested is the leap from there to a tradeable regime — and the settings, which are stale.

The real record

There isn't one, and we are not going to invent one. We checked all 76 strategy configurations on the platform — 19 live, 17 out-of-sample, 36 archived, 4 draft — and all 88 saved strategy versions. Not one mentions this signal. No bot has ever been armed with it, so there are no trades, no fills, no evaluations and no profit or loss to report.

It is the fourth and last of the signals riding crypto_poller, and like the other three it has no bot. We poll it 288 times a day — or would, if half the polls weren't dying on a lock — and nothing reads it. That is an honest fact about the shelf rather than a secret, which is why it's on the page.

How to actually use it

Where to go next

The other three signals on this same poller are written up: crypto_momentum_anchor, btc_dominance_anchor and stablecoin_share_anchor, which share one CoinGecko request between them. All four share the seven-day prune of catch #6, the validation gap of catch #8, and the fact that not one of them has ever been used by a bot.

For the other signal whose only shipped setting cannot open, see btc_dominance_anchor. For the other case of a gate with no hysteresis crossing its own line repeatedly, see finance_anchor. For a signal built on our own history rather than a vendor's, see resolution_anchor. The full list is in the Trade Bot Dictionary.

Every number on this page was measured on 11 August 2026 from the production database, the module source, or a live call to the named endpoint. Where a figure comes from a different series than the one our gate reads, the page says so and gives the method. Nothing here is estimated, rounded up, or carried over from memory. If you find a figure you can't reproduce, tell us — that's a bug in the page.