Trade Bot Dictionary · Crypto

funding_anchor

funding_anchor is a master switch wired to what it costs to hold a leveraged crypto bet. Every thirty minutes we ask OKX for the funding rate on the Bitcoin, Ether and Solana perpetual swaps — the fee that leveraged longs pay leveraged shorts every eight hours, or the other way round when it goes negative — and you pick a condition off it: "only when BTC funding is below 0", "only when it's above 0.05". While your condition holds the bot trades; while it doesn't, the bot places no trades at all that cycle, in any market.

Bots using it
0 live or out-of-sample — 1 archived, which really traded
Data source
OKX /api/v5/public/funding-rate
Refresh
Every 30 minutes (*/30 * * * *) — but see catch #1
Rows stored
4,182 readings 3 coins × 1,394 · 30 days
Backtest-replayable
No — see catch #5
Anchor module
quants/funding_anchor.py

What a funding rate actually is

A perpetual swap is a futures contract with no expiry date. That creates a problem: with nothing forcing it to converge on anything, its price can drift away from the actual spot price of the coin forever. The fix is a payment. Every eight hours — at 00:00, 08:00 and 16:00 UTC on the contracts we poll — everyone holding a position pays or receives a small percentage of their position's value. If the perp is trading above spot, longs pay shorts, which makes being long more expensive and nudges the price back down. If it's below, shorts pay longs. That payment rate is the funding rate, and it is the number this signal reads.

The rates are small and the units matter. Our column is stored as percent per eight hours, so 0.01 means one hundredth of one percent of your position, three times a day — about 11% a year if it held. Everything on this page is in those units.

The reason a trader cares is that funding is a price nobody quotes deliberately. It falls out of how badly one side wants leverage. The module's own docstring puts the usual reading like this: "Positive funding = longs pay shorts (crowded/over-leveraged longs → reversal risk); negative = crowded shorts." That reading is popular, it is roughly the reason the signal exists — and, as catch #3 gets into, at the levels this feed actually produces it is mostly wrong.

Where the data comes from

One vendor, one endpoint, no key, no account: https://www.okx.com/api/v5/public/funding-rate?instId=BTC-USDT-SWAP. Called live from the production server while writing this page it returned HTTP 200 in 0.12 seconds. The poller asks it three times, once each for BTC-USDT-SWAP, ETH-USDT-SWAP and SOL-USDT-SWAP, with a tenth of a second between calls.

OKX is not the obvious choice and the poller says why in its own docstring: "Binance & Bybit are geo-blocked from the Hetzner datacenter; OKX works." That is a deployment fact rather than a view about which exchange is best, and it is worth knowing — the funding rate you see here is one venue's funding rate, not the market's.

The fetcher is predictive/funding_poller.py on cron */30 * * * * — 48 cycles a day, 144 rows. It takes the fundingRate field, multiplies by 100, rounds to five decimals and writes a row into crypto_funding in predictive.db along with the raw decimal and the timestamp of the settlement the rate applies to. Rows older than 30 days are deleted on each run. The gate function in quants/funding_anchor.py then reads the single most recent row for your chosen coin and compares it to your number.

OKX has never once failed us. Across the poller's entire log — 6,723 lines — the string fetch failed appears zero times. Every failure in that log, and there are 217 of them, is our own database refusing to be written to. Catch #1 is about that.

How funding_anchor gets from OKX to a trade decision, where the threshold we document sits against three months of real funding rates, what the one bot that used it actually did, and the lock arithmetic that has killed the feed for 52 hours The first band traces the data path. The source is OKX's public funding-rate endpoint at www dot okx dot com slash api slash v5 slash public slash funding-rate — free, no key, no account, which answered in 0.12 seconds when called live from the production server on the twelfth of August 2026. Our poller, predictive slash funding underscore poller dot py, runs on a cron of star slash thirty, meaning every thirty minutes, 48 times a day, and asks for three instruments: the Bitcoin, Ether and Solana USDT perpetual swaps. It writes rows into the crypto underscore funding table in predictive dot db, which holds 4,182 readings covering the tenth of July to the ninth of August 2026 and is pruned to thirty days. The gate function in quants slash funding underscore anchor dot py asks whether the newest reading for your coin is above or below your chosen rate, and is supposed to refuse to answer 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. One bot has ever been downstream of it and it is archived. The band is marked with the four things that go wrong: the feed is 52 hours stale, the staleness check does not actually work, the stored number is a forecast rather than a settled fact, and the gate applies to every market rather than just crypto ones. The second band plots every one of the 278 funding settlements OKX will serve for the Bitcoin perpetual — three months, from the eleventh of May to the twelfth of August 2026 — as a line, in percent per eight hours. A zero line runs across the middle; the series crosses it repeatedly, spending 55 of 279 settlements negative. A solid line marks 0.01 percent, and the series touches it exactly 21 times and never once goes above it: that value is a structural pin, not a coincidence. Far above the top edge of the chart, off the plotting area entirely, an arrow marks 0.05 percent per eight hours — the threshold used as the example in our module's own docstring. It is roughly five times higher than anything in the recoverable history. A second marker shows OKX's own documented ceiling for this contract, 0.375 percent, which is thirty-seven times higher again and shows that 0.05 is a hot-market number rather than an impossible one. The third band is the record of the only bot that ever used this signal, Crypto Fear Reversion, over the twenty-six hours it was alive on the eleventh and twelfth of June 2026. Along the bottom, five Bitcoin funding settlements recovered from OKX's public history: minus 0.00435, minus 0.00603, minus 0.0024 and minus 0.0005, all below zero, then plus 0.00134 at eight in the morning on the twelfth, which is where the rate turns positive. The bot's gate required funding below zero, so the shaded region showing the gate open runs from the start until that crossing. Twelve trade markers sit above the funding line, four green wins and eight red losses, and every single one falls inside the shaded open region. The last trade is at 05:20 on the twelfth, under three hours before the gate closed. The gate did exactly what it was designed to do; the trades still lost 12 dollars and 92 cents. The fourth band is the arithmetic of the outage. A red bar shows our backtest index job, predictive dot ticker underscore index, which runs every ten minutes on the zero minute and holds the write lock on predictive dot db for 119 seconds — measured at between 118.4 and 124.2 seconds over the last six runs. Below it, eight pollers are drawn as bars starting at their cron offset within the ten-minute cycle and running as long as their SQLite busy timeout. A poller survives only if its bar reaches the end of the red one. funding underscore poller starts at second zero with a ten-second timeout and dies at ten seconds. Tropical, space launch and sports edge start at zero with thirty seconds and die. GDPNow and sentiment start at zero and forty with sixty seconds and die. The wiki pageviews poller starts sixty seconds in with thirty seconds and dies at ninety. The MLB bullpen poller starts sixty seconds in with twenty seconds and dies at eighty. The ensemble poller starts sixty seconds in with a sixty-second timeout, reaching 120 seconds, and survives by roughly one second. The heat index poller starts at minute thirty-five, five minutes clear of the lock, and never collides at all. Every stale feed on the platform is on the dead side of that line and every healthy one is on the living side. 1 · Source → poller → table → gate → your bot OKX /api/v5/public/ funding-rate free · keyless · 0.12 s 0 failures ever funding_poller */30 * * * * BTC · ETH · SOL swaps every write fails crypto_funding predictive.db 4,182 rows · 30 days newest is 52 h old the gate above / below ? stale > 90 min → check is broken the whole bot trades / stands down 1 bot ever archived · −$12.92 one venue, not the market dies on our own lock (band 4) stores a forecast, not the settled rate any row from today passes gates every market 2 · Every funding settlement OKX will serve, against the threshold our docs suggest 278 eight-hourly settlements, BTC-USDT-SWAP, 11 May – 12 Aug 2026, from /api/v5/public/funding-rate-history — free, keyless, HTTP 200. Percent per 8 h. 0.05 — the example in our own docstring (off scale) 5× the highest value in three months … … but OKX's cap here is 0.375, so it is a hot-market number, not an impossible one 0.012 0.010 0 −0.008 0.01 — touched exactly 21×, never exceeded the 30 days we keep — everything older is deleted 11 May 11 Jun 11 Jul 12 Aug Below zero on 55 of 279 settlements (19.7%) — which is the one threshold our builder actually offers, and it works. 3 · The only bot that ever used it — “Crypto Fear Reversion”, 11–12 June 2026 Its gate was {"symbol":"BTC","below":0}. The readings that opened it were deleted by our own 30-day prune; these are the settled rates, recovered from OKX. gate OPEN — BTC funding below 0 gate SHUT 12 trades 6 in the first 3½ h, 6 more overnight 0 −0.00435 −0.00603 −0.00240 −0.00050 +0.00134 11 Jun 00:00 08:00 16:00 12 Jun 00:00 08:00 Every trade fell inside the open window, the last one 2 h 40 m before it shut. The gate worked exactly as designed — and the bot went 4–8 for −$12.92. 4 · Why the feed is dead: one 10-minute cycle on predictive.db A poller lives only if its SQLite busy timeout outlasts the write lock. Measured, not modelled — timeouts read from source, lock duration from the last six index runs. :00 +50 s +100 s +150 s +200 s ticker_index */10 · 543k tickers holds the write lock — 119 s funding_poller :00 +10s dies at 10 s tropical · launch · sports :00 +30s dies at 30 s gdpnow :30 +60s dies at 60 s sentiment (F&G) :40 +60s dies at 60 s wiki pageviews :11 +30s dies at 90 s mlb bullpen :41 +20s dies at 80 s ensemble spread :41 +60s survives — by about 1 second Every stale feed on the platform sits left of the red line. Every healthy one clears it, or starts far enough into the cycle never to meet it — like heat_index at 35 */3, five clear minutes away. Nothing here is about the vendor, the network, or the data. It is our own backtest index. Same mechanism the onchain_fees_anchor page measured as a 50% sample loss: that poller runs */5, so half its fires land at :x5, five minutes clear, and live.
Band 2's series is OKX's realized settled rates, which is a different series from the forward estimate our poller stores — see catch #4. Band 3's funding values were recovered from that same public history because our own 30-day prune had already deleted the readings the bot actually traded on. Band 4's timeouts were read out of each poller's source and the lock duration from the last six ticker_index runs (118.4–124.2 s).

What it means for your bot

It is a switch on the whole bot, not a filter on crypto markets. The gate runs once per cycle, before any market is looked at. If BTC funding doesn't satisfy your condition, your bot places no trades that cycle — in weather, in baseball, in Fed markets, anywhere. Nothing in the code restricts it to crypto. If you want "trade crypto only when…", you need the category filter as well; this signal on its own will happily stand your weather bot down over the cost of leverage on a Solana swap.

The realistic use is the one our builder actually offers: below 0. Negative funding means shorts are paying longs, which is the unusual state — it happened on 19.7% of the 279 settlements OKX will serve, and on 12.3% of our BTC readings. As a way of saying "only when the leverage crowd is leaning short", it is a real, reachable, meaningful condition. Whether leaning against it makes money is a separate question, and the one bot that tried it is in the record below.

The catch

1. The feed has been dead for 52 hours, and it is our fault, not OKX's

The newest row in crypto_funding is from 2026-08-09T22:00:04Z. At the time of writing that is 52.5 hours ago. The poller has fired about 105 times since and inserted nothing. Every one of those runs fetched the data from OKX successfully and then died writing it, with sqlite3.OperationalError: database is locked104 consecutive failures since the last success.

The cause is predictive.ticker_index --refresh, our backtest lookup index. It runs */10 over 543,000 tickers and holds the write lock on predictive.db for 119 seconds — 118.4, 118.6, 118.9, 119.1, 120.6 and 124.2 seconds on the last six runs. funding_poller opens its connection with timeout=10 and fires at :00 and :30 — both of which are ticker_index minutes. It waits ten seconds for a lock that will not be free for another 109, and gives up. It is not unlucky; at that cadence it is never going to win.

This is not one broken feed. Running signal_health.py shows seven stale feeds — Fear & Greed (74.5 h), perp funding (52.5 h), MLB model edge (52.5 h), tropical formation (53.5 h), launch schedule (53.5 h), GDPNow (69 h) and Wikipedia attention (53.3 h). One rule sorts every poller on the box correctly: a poller survives if the seconds from its start to the end of the lock are fewer than its busy timeout. Band 4 of the diagram draws it. The clearest case is a pair that both run at :41, 60 seconds into the lock: ensemble_poller waits 60 seconds and lives; mlb_bullpen_poller waits 20 and dies.

Not fixed here — this page's job is the dictionary, and the loop that writes it is not allowed to touch pollers or crontabs. It has been reported. What is worth saying on a page about the signal is that the data was never the problem: OKX answered every single time.

2. The staleness check that should have caught this does not work

The gate is meant to fail closed. It asks for the newest row AND fetched_at >= datetime('now', '-90 minutes'), and if nothing comes back it returns False. The idea is right. The comparison is broken.

We store timestamps in Python's ISO format — 2026-08-12T00:00:02.111+00:00, with a T between the date and the time. SQLite's datetime() returns 2026-08-12 00:56:43, with a space. Comparing them compares text, and "T" sorts after " ". So the date matches, then the T wins, and the row passes. Run on production while writing this page:

SELECT '2026-08-12T00:00:02.111+00:00' >= datetime('now','-90 minutes'); → 1

The reading was 2 hours 26 minutes old. The window is 90 minutes. It passed. In practice any row stamped with today's UTC date passes the freshness check, however old it is — up to almost 24 hours just before midnight. The gate only genuinely fails closed once the data is stale enough to be from a previous date, which is why it happens to be failing closed today. Same defect as finance_anchor and tropical_anchor; the four signals on crypto_poller get it right. Unfixed.

For what it is worth, the 90-minute window was needed before all this: across the 1,394 healthy cycles there were 6 gaps longer than 90 minutes and 44 longer than an hour, the largest being 150 minutes.

3. Our own documented example has never been reachable — and “positive means crowded longs” is wrong at these levels

The module's docstring offers this as its worked example: {"symbol":"BTC", "above": 0.05}, annotated "crowded longs". Across our 4,182 readings, the number of times any coin reached 0.05 is zero. Across all 279 settlements OKX will serve — three months — the number of times BTC funding reached 0.05 is also zero. The highest value in either data set is 0.01.

In fairness, 0.05 is not a silly number, and this is where a second opinion changed the page. OKX returns its own ceiling in the same payload: maxFundingRate is 0.375 for the BTC contract and 0.75 for ETH and SOL — thirty-seven and seventy-five times higher than anything we have observed. 0.05% per 8 h is roughly 55% a year in carry; that is a hot, over-leveraged market, and it is a normal thing for funding to do. It is a hot-market threshold that has not seen a hot market. That is a different failure from onchain_fees_anchor, whose shipped 10 sat/vB is a number the chain last touched twenty months ago.

What is genuinely strange is the 0.01. Of 279 settlements, 21 came in at exactly 0.01 and not one exceeded it. A continuous quantity does not land on the same five-decimal value twenty-one times by chance, so 0.01 is structural, not a calm-market coincidence — and note that it is exactly the interestRate field OKX returns alongside the rate (0.0001). The standard account of this is a dead-band: while the perp's premium over spot stays inside a band, the funding rate collapses to precisely the interest rate. We are not asserting that formula, because we tested it against a live payload and it did not reproduce OKX's number — although that may simply be because the published formula uses a time-weighted average premium and the API exposes only an instantaneous one. Verified: the pin is real and it is at 0.01. Unverified: exactly why.

The consequence for the reader is the part that matters. If 0.01 is where funding sits when nothing is happening, then a positive funding rate is the default state of the world, not evidence of crowded longs. Our docstring's gloss — positive means over-leveraged longs and reversal risk — describes genuinely elevated funding, which this feed has not seen. Read the 0.01 readings as "normal", not "bullish".

4. You are thresholding a forecast, not a settled fact

/api/v5/public/funding-rate returns the rate for the settlement that has not happened yet, and it keeps moving until it does. Our poller stores that number — 16 times per 8-hour window — and the gate compares your threshold against whichever version happened to be captured last.

How much does it move? Within a single settlement window, the estimate for BTC wanders an average of 0.0047 and as much as 0.0103. The entire 30-day range of the series is about 0.021 wide. The number moves roughly a quarter of its whole monthly range before it settles, and in the worst window it moved half of it. And for the one threshold anybody actually uses — the builder's below 0 — the estimate was on both sides of zero in 106 of the 279 settlement windows we captured across the three coins, 38%. In more than a third of windows, "is funding negative" had two different answers depending on when you asked.

The settled rate is available and we throw it away. The same payload carries settFundingRate; we confirmed it matches the realized rate for the previous settlement exactly (0.0000495294037917 in both the live response and the history endpoint). We store the forecast and discard the fact.

5. The backtester cannot replay it

funding_anchor is listed in _UNSUPPORTED_ENTRY in quants/backtest.py, added 2026-06-04 with the note that these anchors "need a forward-captured series we don't have retroactively". So a backtest of a bot with this gate runs without the gate and still returns an equity curve. It flags unsupported_rules; you have to look.

Here the stated excuse is only half true, and worth correcting. We do now have a retroactive series: OKX's funding-rate-history endpoint is free, keyless, and served three months of realized eight-hourly settlements in 0.12 seconds when we called it. That is not the same series the live gate reads — it is the settled rate, not the forward estimate — but it is a defensible one to replay against, and arguably a better one. What is real is the depth: pagination stopped at 279 settlements, so three months is all OKX will give, against price history that starts 22 June anyway.

6. Thirty days of memory — and it deleted the only evidence we had

Each run deletes rows older than 30 days. That prune has the same string-comparison quirk as catch #2 in reverse: because the ISO T sorts high, rows survive to the end of their final day, so real retention is 742 hours rather than 720. Harmless, and much milder than the seven-day version on the crypto_poller signals.

What is not harmless is the consequence. The one bot that ever used this signal traded on 11–12 June. The funding readings it traded on no longer exist. We could only reconstruct band 3 of the diagram — the thing that shows the gate actually worked — by going back to OKX's public history, because our own copy had been thrown away. A year of this series would be about 52,000 rows.

7. A live page is showing you a 52-hour-old number, and its labels have never once fired

The Opportunity scanner has a "crowded leverage" panel that reads this same table. Its query is SELECT funding_pct … ORDER BY fetched_at DESC LIMIT 1 — with no freshness filter at all, not even the broken one. Right now it is presenting Saturday night's funding rate as the current state of the market.

And its thresholds cannot fire. It labels a coin "crowded longs" at ≥ 0.03 and "crowded shorts" at ≤ −0.03. Across all 4,182 readings we hold, the number that met either condition is zero. Every reading in the table's entire history has been labelled "neutral", and given the 0.01 pin in catch #3, that will stay true until the market changes character.

8. Two smaller things: the registry mis-reads the poller, and the validator lets you write nonsense

  • The registry cannot find this signal's poller. signal_registry.py reports poller: "db" and cron: null, which would suggest nothing fetches this data. It does. The cause is one regex: the registry looks for predictive\.(\w+) in the docstring, and the docstring's second sentence begins "Reads predictive.db.crypto_funding (funding_poller, OKX)". It matches predictive.db, captures db, and never reaches the fallback that would have found funding_poller.py sitting right there. The same artefact hits five signals — this one plus energy, launch, sports and tropical. Everything else the registry says is correct.
  • There is no bound on the threshold. validate_config checks only that your number is a number. {"symbol":"BTC","above":100} validates happily — 100% per 8 h, roughly 266 times OKX's own cap.
  • A contradictory config validates, and then hides half of itself. {"symbol":"BTC","above":0.05,"below":-0.02} passes validation and can never be satisfied, because the gate requires both. Worse than the equivalent bug elsewhere in the library: to_english checks above first and returns, so the builder tells you "only when BTC funding ≥ 0.05% / 8h (crowded longs)" and never mentions the second condition at all. Elsewhere the two clauses at least both get printed.

The case for the defence

  • It is the steadiest gate in the crypto shelf, by a wide margin. At the builder's below 0 setting the gate changes state 1.4 times a day, with a median run of 17 polls — 8.5 hours, almost exactly one settlement period. onchain_fees_anchor flips 20.9 times a day at its usable threshold. Funding is a genuine regime variable rather than a strobe, and it is that way for a structural reason: the underlying thing only settles three times a day.
  • The builder's default is honest. The field ships at below 0 and the one-click recipe, "Funding mean-reversion", uses the same. That condition is open 12.3% of the time on BTC and 23.6% across the three coins. The unreachable 0.05 is in the docstring only — the number a user is actually handed is a good one. That is the opposite of the pattern on three other pages in this dictionary.
  • The gate demonstrably did its job. Reconstructing June from OKX's history: BTC funding settled negative at every settlement from 11 June 00:00 through 12 June 00:00, and turned positive at 12 June 08:00. The bot's twelve trades run from 11 June 03:45 to 12 June 05:20 — all inside the negative stretch, stopping before the flip. The signal fired when it said it would.
  • The vendor choice was right and the vendor is flawless. Zero fetch failures in the entire log, 0.12-second responses, no key, no account, and a free three-month history endpoint most paid providers charge for. Every failure this signal has ever had was ours.
  • It is genuinely independent. Nothing else in the signal library reads leverage positioning. It is not a price, not a poll, not a forecast, and not derived from anything else on the shelf — which is exactly what you want from a gate you intend to combine with others.

The real record

One bot has ever used this signal, and unlike the four Tier-2 signals written up before it, this one actually traded. Of the 76 strategy configurations on the platform — 21 live, 15 out-of-sample, 36 archived, 4 draft — exactly one mentions funding_anchor: Crypto Fear Reversion (crypto-fear-reversion, id 31), now archived. Its own description says what it was for: "buy mid-band crypto dips ONLY at crowd-capitulation (Fear&Greed<20 + funding<0 + 8c drop)… May fire rarely; drop funding gate first if <2 fills/wk."

It was created at 03:42 UTC on 11 June 2026 and it fired twelve times in the next 25 hours 35 minutes. All twelve were Polymarket, all YES, all $5 flat.

MarketEntryResultP&L
Will Bitcoin dip to $60,000 June 8–14?37¢loss−$5.00
Will Ethereum dip to $1,600 June 8–14?51¢loss−$5.00
Will BTC be between $60,000 and $62,000 on June 11?25¢loss−$5.00
Ethereum Up or Down on June 11?44¢loss−$5.00
Solana Up or Down on June 11?37¢win+$8.51
Bitcoin Up or Down on June 11?53¢win+$4.43
Bitcoin Up or Down — June 11, 8PM ET53¢win+$4.43
Bitcoin Up or Down — June 11, 4–8PM ET34¢win+$9.71
Will Bitcoin reach $64,000 on June 11?37¢loss−$5.00
Will BTC be above $64,000 on June 12?33¢loss−$5.00
Bitcoin Up or Down — June 11, 8PM–12AM ET36¢loss−$5.00
Will BTC be between $64,000 and $66,000 on June 12?26¢loss−$5.00
12 trades · 4 wins, 8 losses · $60.00 staked33.3%−$12.92

That is the whole track record of this signal, and the lesson in it is the useful one. The gate was not broken, was not stale, and was not mis-set. It opened when BTC funding was negative, exactly as designed, and it shut the bot down when funding turned. It did its job, and the bot lost 21.5% of the money it staked in a day. A gate that works is not an edge; it only decides when you are allowed to be wrong.

Since that bot was archived: nothing. No live bot, no out-of-sample bot, and none of the 88 saved strategy versions except the one belonging to this bot. We have polled OKX 48 times a day ever since — or would, if the writes were landing.

How to actually use it

Where to go next

For the crowd-sentiment gate this bot was paired with, see sentiment_anchor — which is also one of the seven feeds currently stale. For the other signals on the crypto shelf, none of which has ever had a bot at all, see crypto_momentum_anchor, btc_dominance_anchor, stablecoin_share_anchor and onchain_fees_anchor, whose page first measured the lock contention described in catch #1.

For the same broken string-comparison in a freshness check, 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 12 August 2026 from the production database, the module source, the live crontab, or a live call to the named endpoint. Where a figure comes from a different series than the one our gate reads — OKX's settled rates rather than our stored forecasts — the page says so. Where we could not establish a mechanism, the page says that too. Nothing here is estimated or carried over from memory. If you find a figure you can't reproduce, tell us — that's a bug in the page.