Break down a rule
MCP tool: breakdown
Shows where a rule works and where it does not. A rule that looks good overall is often one category carrying four.
Buckets with fewer than 10 settled trades are noise and are dropped rather than reported. Results are sorted by return, best first.
Body parameters
criteriaobjectrequiredThe rule: which trades to include. The same shape a saved strategy uses, so a rule you test is a rule you can deploy without translation.
platformsstring[]Venues to include: "polymarket", "kalshi". Omit for both, which is usually right.
categoriesstring[]Market categories: "sports", "politics", "crypto", "finance", "culture". Omit for all.
sportsLeaguesstring[]Leagues, e.g. ["NBA", "NFL"]. Only applies to sports markets. Max 20.
minAmountUsdnumberMinimum trade size in USD. Typical values are 10000 to 50000.
maxAmountUsdnumberMaximum trade size in USD. Must be at least minAmountUsd when both are set.
priceMinnumberMinimum entry price, 0 to 1. 0.75 and up is heavy favourites.
priceMaxnumberMaximum entry price, 0 to 1. 0.20 and below is longshots. Must be at least priceMin when both are set.
eventTypesstring[]How the trade changed the trader's position: "open", "add", "flip", "trim", "close", "unknown". Entries only is ["open", "add", "flip"], which is the usual choice. Trims and closes are exits and never settle, so they cannot be scored.
directionsstring[]Trade direction: "buy_yes", "buy_no", "sell_yes", "sell_no". Only buys are ever scored; sells never resolve.
keywordsstring[]Case-insensitive substrings matched against the market name. Any one matching is enough. Max 10.
bystringrequiredThe dimension to split on: "category", "platform", "month", "price_band".
stakenumberdefault: 100Hypothetical stake per trade in USD, 1 to 1000000. Return percentage is stake-invariant.
sinceDaysintegerdefault: 90Lookback window in days, 1 to 365.
Response
One result per bucket, each a full backtest result plus the bucket it covers.
curl -X POST https://api.rivo.markets/v1/backtest/breakdown \
-H "Authorization: Bearer rivo_live_..." \
-H "Content-Type: application/json" \
-d '{
"criteria": {
"priceMax": 0.2,
"minAmountUsd": 10000
},
"by": "category"
}'import requests
r = requests.post(
"https://api.rivo.markets/v1/backtest/breakdown",
headers={"Authorization": "Bearer rivo_live_..."},
json={
"criteria": {
"priceMax": 0.2,
"minAmountUsd": 10000,
},
"by": "category",
},
)
print(r.json()["data"])const res = await fetch("https://api.rivo.markets/v1/backtest/breakdown", {
method: "POST",
headers: {
Authorization: "Bearer rivo_live_...",
"Content-Type": "application/json",
},
body: JSON.stringify({
criteria: {
priceMax: 0.2,
minAmountUsd: 10000,
},
by: "category",
}),
});
const { data } = await res.json();{
"success": true,
"data": {
"by": "category",
"results": [
{
"bucket": "sports",
"matched": 112,
"settled": 98,
"wins": 31,
"losses": 67,
"open": 14,
"winRate": 0.316,
"stakeUsd": 100,
"stakedUsd": 9800,
"pnlUsd": 9992,
"returnPct": 104,
"window": { "sinceDays": 90, "stake": 100 }
},
{
"bucket": "culture",
"matched": 331,
"settled": 312,
"wins": 66,
"losses": 246,
"open": 19,
"winRate": 0.212,
"stakeUsd": 100,
"stakedUsd": 31200,
"pnlUsd": 8736,
"returnPct": 28,
"window": { "sinceDays": 90, "stake": 100 }
}
]
}
}