How to Detect Edge Decay in Your Trading Bot
>This covers the detection system. Polymarket Profits 2 ties edge-decay alerts into the portfolio rebalancer so capital moves to healthier strategies automatically.

Summary:
- Edge decay is math, not failure. Every profitable strategy gets less profitable as bots enter.
- Five metrics tell you when decay is happening before your P&L turns red.
- The
PlatformChangeMonitorclass catches fee updates and tick-size changes as leading indicators.- Stop, pivot, adapt, or add — a decision framework that tells you what to do with a decaying strategy.
The arbitrage scanner that printed money last month is making half as much this month. Fill rates on your limit orders dropped from 80% to 55%. Your win rate is the same but the average profit per trade is shrinking. That is edge decay, and the last month of Polymarket changelog entries proves it is happening faster than ever.
Four platform changes in the past 11 days that would each break a bot running on last-month’s assumptions: new pagination endpoints, fee structure V2 with updated per-category rates, a change to how the closed query parameter defaults, and a new feeSchedule object that replaces the old fee fields. A bot that skipped these updates is trading against stale rules and losing money to mechanics it cannot see.
What is edge decay?

Edge decay is the process by which a profitable trading strategy loses profitability over time as competing bots enter the market, platform rules change, or the underlying inefficiency closes. Every edge has an expiration date.
Decay happens in four phases, and knowing which phase your strategy is in tells you how much longer it will print money:
- Discovery. A few traders find the strategy. Nobody else runs it. Returns are high and stable.
- Imitation. Others figure it out. Reddit posts, books, and courses spread the knowledge. Competition increases.
- Crowding. Hundreds of bots run the same play. Gaps close in milliseconds instead of seconds. Slow bots go negative.
- Equilibrium. Only the most efficient operators profit. Margins are thin. The bar to enter profitably is high.
Most Polymarket strategies from Polymarket Profits 2 are in Phase 1 or Phase 2 right now. Your job is not to fight decay — that is a losing battle. Your job is to detect which phase each strategy is in and rotate capital before the edge turns negative.
How do you detect edge decay from your trade log?
You track the average profit per trade over a rolling 30-day window and compare it to the prior 30-day window. A 30%+ drop is a red flag. Here is the function:
def detect_edge_decay(trade_log, window=30):
"""Detect whether average profit per trade is declining.
trade_log List of dicts with a 'pnl' key in dollar terms.
window Number of trades in each comparison window.
Returns dict with recent_avg, previous_avg, decay_pct, and
alert (True when decay > 30%).
"""
if len(trade_log) < window * 2:
return None # Not enough data yet
recent = trade_log[-window:]
previous = trade_log[-window * 2:-window]
recent_avg = sum(t["pnl"] for t in recent) / len(recent)
previous_avg = sum(t["pnl"] for t in previous) / len(previous)
if previous_avg == 0:
decay_pct = 0
else:
decay_pct = (previous_avg - recent_avg) / abs(previous_avg) * 100
return {
"recent_avg_pnl": recent_avg,
"previous_avg_pnl": previous_avg,
"decay_pct": decay_pct,
"alert": decay_pct > 30,
}
Profit per trade is the primary metric, but it is a lagging indicator. By the time your trade log shows decay, the edge has been shrinking for weeks. The other four metrics catch it earlier.
The 30% alert threshold is a starting default, not a statistical guarantee. Tune it to your trade volume and PnL variance: if your strategy has high variance (wide win/loss spread), a 30% drop over 30 trades may be noise, and you want a wider window or a tighter threshold. Run the decay check against your own historical log before trusting the default.
Which five metrics do you track?
You track profit per trade, limit order fill rate, time to fill, win rate stability, and platform-change events. The first four are lagging signals from your own data. The fifth is a leading signal from Polymarket itself.
| Metric | Signal | What it means when it drops |
|---|---|---|
| Avg profit per trade | Lagging | Spreads are tightening, edge is closing |
| Limit order fill rate | Lagging | Other bots are grabbing liquidity before you |
| Time to fill | Lagging | You are losing the speed race |
| Win rate stability | Lagging | Market structure is changing |
| Platform-change events | Leading | Metadata flipped, recalculate edge now |
Two or more lagging signals moving in the same direction is the condition for reducing allocation. A single platform-change event is the condition for pausing new entries until you have recalculated edge on every active position.
How do you catch platform changes before they hit your P&L?
You diff the market metadata fields your strategies depend on and fire an alert when any of them change. This is the leading indicator that the other four metrics cannot give you.
import time
class PlatformChangeMonitor:
"""Watch Polymarket metadata for the kinds of changes that
decay your edge instantly: fee activations, rate changes,
tick size changes, negRisk flag flips, category reassignments.
Tracks BOTH the legacy fee fields (feeRateBps, feesEnabled)
AND the new feeSchedule object introduced Mar 31, 2026. Either
field disappearing or changing is a signal to recalculate edge.
"""
TRACKED_FIELDS = [
"feeRateBps", # legacy
"feesEnabled", # legacy
"feeSchedule", # new (Mar 31, 2026)
"minimum_tick_size",
"negRisk",
"category",
]
def __init__(self):
# token_id -> {field_name: last_seen_value}
self.snapshots = {}
def snapshot(self, market):
"""Record current metadata for a market."""
token_id = market.get("tokens", [{}])[0].get("token_id")
if not token_id:
return
self.snapshots[token_id] = {
f: market.get(f) for f in self.TRACKED_FIELDS
}
def check_for_changes(self, markets):
"""Compare current metadata to last snapshot.
Returns a list of detected changes. Run on every scan
cycle, or at least every 5 minutes.
"""
changes = []
for market in markets:
token_id = (
market.get("tokens", [{}])[0].get("token_id")
)
if not token_id:
continue
if token_id not in self.snapshots:
self.snapshot(market)
continue
previous = self.snapshots[token_id]
current = {
f: market.get(f) for f in self.TRACKED_FIELDS
}
for field in self.TRACKED_FIELDS:
if previous.get(field) != current.get(field):
changes.append({
"token_id": token_id,
"field": field,
"previous": previous.get(field),
"current": current.get(field),
"question": market.get("question", "")[:60],
"timestamp": time.time(),
})
self.snapshots[token_id] = current
return changes
Plug this into your main scanner loop. Any non-empty return means: stop opening new positions in that market, re-run edge calculation on every active position, and log the change.
How fast do Polymarket platform changes actually happen?
Faster than most bot operators realize. Pulled from the official Polymarket changelog, here are the changes in the 11 days before this article was written:
| Date | Change | Impact on bots |
|---|---|---|
| Apr 10, 2026 | New keyset pagination endpoints (/markets/keyset, /events/keyset) | Offset-based pagination will be deprecated; old code will break |
| Apr 9, 2026 | GET /markets closed parameter defaults to false | Bots relying on old default now miss resolved markets |
| Mar 31, 2026 | Fee calculation now uses feeSchedule object | Hardcoded feeRateBps parsers break silently |
| Mar 30, 2026 | Fee Structure V2 — updated rates per category | Every bot sizing against old fee rates is mispricing trades |
Four changes in 11 days. Three of them directly affect the metadata your bot depends on. If you deployed your scanner on March 15 and have not updated it since, the bot is now trading against rules that do not exist. The PlatformChangeMonitor above catches the last two automatically. The pagination change you have to read the changelog for.
When should you stop, pivot, adapt, or add?
You apply the four-way decision framework based on what the decay signals are telling you.
| Decision | Condition | Action |
|---|---|---|
| Stop | Decay exceeds 50% over 30 days AND cause is structural (permanent competition, fee increase) | Kill the strategy. Redeploy capital elsewhere. |
| Pivot | Same strategy works on different markets | Point the scanner at fresh categories (new launches, niche markets) |
| Adapt | A parameter change restores profitability | Raise min spread, tighten depth filter, switch taker to maker |
| Add | New edge appears alongside the decaying one | Run both in parallel while the old one still has some edge |
The trap most bot operators fall into: they refuse to stop. They burned weeks building the strategy and cannot bring themselves to kill it. Do not confuse sunk cost with current edge. A strategy that worked for three months and now loses money is a sunk cost. The next month of losses is your future to choose.
Pivoting is the most underused option. Your arbitrage scanner that is dying on BTC time-series markets because 50 other bots run the same play? The code works. The markets are the problem. Point it at a newly launched category where you are the first bot in and you are back in Phase 1.
Here is the framework as a function you can call from your weekly monitoring job:
def decide_strategy_action(decay_report, fill_rate, cause):
"""Recommend stop, pivot, adapt, or add for a decaying strategy.
decay_report Output of detect_edge_decay() or None.
fill_rate Current limit-order fill rate, 0.0-1.0.
cause "competition" | "fees" | "market_shift" | "unknown".
"""
if decay_report is None:
return ("MONITOR", "Not enough trades yet.")
decay_pct = decay_report["decay_pct"]
if decay_pct > 50 and cause in ("competition", "fees"):
return ("STOP", f"Structural decay {decay_pct:.0f}%. Redeploy capital.")
if fill_rate < 0.4 and cause == "competition":
return ("PIVOT", "Fills collapsing. Point scanner at new categories.")
if decay_pct > 30 and cause == "market_shift":
return ("ADAPT", "Raise min spread, tighten filters, switch maker/taker.")
if decay_pct > 15:
return ("ADD", "Run a complementary strategy in parallel.")
return ("MONITOR", f"Decay {decay_pct:.0f}% is within noise.")
Call it every Sunday with fresh trade-log data. It turns “I have a gut feeling something is off” into a specific recommendation you can argue with.
The PlatformChangeMonitor and detect_edge_decay() functions sit alongside the paper-trading trainer from Chapter 3 of Polymarket Profits 2. Every strategy that runs through the trainer also feeds its trades into these two detectors. When the trainer starts showing you declining profit per trade, decay has already begun, and the monitor tells you whether it was competition or a platform change before P&L makes it obvious.
Related in this series
- Polymarket Trading Fees: The Real Formula. The fee fields the monitor tracks for platform changes.
- Polymarket Position Sizing With Fee-Adjusted Kelly. Shrink Kelly when decay crosses the threshold.
- How to Build a Polymarket Resolution Scanner. The strategy with the fastest decay profile.
- How to Build a Contrarian Bot for Polymarket. The strategy with the slowest decay profile.
What should you actually do?
- Run
detect_edge_decay()on every strategy weekly. Put it in a cron job, send yourself an email alert whendecay_pct > 30. - Run
PlatformChangeMonitor.check_for_changes()on every scan cycle. Platform changes are the one leading indicator, and it costs you nothing to check every 60 seconds. - Read the Polymarket changelog once a week. The metadata monitor catches field flips, but API-level changes (new endpoints, deprecated parameters) require human review.
- Never refuse to stop a decaying strategy. Apply the framework honestly. If decay is structural and adaptation does not work, kill it and move on.
- Always have the next strategy in paper trading. The time to find your next edge is while the current one is still profitable, not after it dies.
bottom_line
- Edge decay is guaranteed, not avoidable. Build the monitoring system before you need it.
- Platform changes are the only leading indicator you get for free. Use them.
- Stop is an option. A strategy that made you money last year owes you nothing this year. Kill it and move on.
Frequently Asked Questions
What is edge decay in a trading bot?+
Edge decay is the gradual loss of profitability as competing bots enter the same market or as platform rules change. A strategy that returned 8% a month last quarter might return 2% this quarter and lose money next quarter as the edge erodes.
How do you know when your trading bot's edge has decayed?+
Track five metrics: average profit per trade, fill rate on limit orders, time to fill, win-rate stability, and platform-change events. Two or more declining together, or a single platform change, is the signal to reduce allocation or pause the strategy.
Should you shut down a decaying strategy or try to fix it?+
Apply the stop/pivot/adapt/add framework. Stop if decay exceeds 50% and the cause is structural. Pivot if the same code works on different markets. Adapt if a parameter change restores profitability. Add a complementary strategy if the current one still has some edge.
More from this Book
How to Build a Contrarian Bot for Polymarket
A Polymarket contrarian bot that uses base rates, engagement-weighted sentiment, and a political-market insider filter. With Python code and examples.
from: Polymarket Profits 2
Polymarket Position Sizing With Fee-Adjusted Kelly
Quarter-Kelly position sizing for Polymarket with the real fee formula, correlation clusters, and why a 68% win rate still loses money. With Python code.
from: Polymarket Profits 2
How to Build a Polymarket Resolution Scanner
A Polymarket resolution scanner that catches events before the price updates. Covers the 4 event types, 15-second staleness check, and edge calculation.
from: Polymarket Profits 2
Polymarket Trading Fees: The Real Formula and Table
The real Polymarket fee formula, taker rates per category from the official docs, and a worked example proving 5%+ effective fees kill most arbitrage bots.
from: Polymarket Profits 2