mirror of
https://github.com/theodore-song/polymarket-analyst.git
synced 2026-08-24 04:58:08 +00:00
Diversify verified bundle search by event
This commit is contained in:
@@ -67,7 +67,9 @@ Each Build 121 cycle also scans the 1,000 most-active Polymarket events for
|
|||||||
complete negative-risk bundles and logically nested threshold or deadline
|
complete negative-risk bundles and logically nested threshold or deadline
|
||||||
pairs. Gamma's market-specific fee flag replaces the old blanket 0.5-cent fee
|
pairs. Gamma's market-specific fee flag replaces the old blanket 0.5-cent fee
|
||||||
reserve for markets declared fee-free. The closest 60 structures are then
|
reserve for markets declared fee-free. The closest 60 structures are then
|
||||||
repriced from batched CLOB asks from the equal-unit size needed for at least a $50
|
ranked by locked-capital efficiency, with the best structure from each independent
|
||||||
|
event checked before alternates from events already represented. They are repriced
|
||||||
|
from batched CLOB asks from the equal-unit size needed for at least a $50
|
||||||
paper order up to a $400 verified-notional ceiling. The scanner applies each market's Gamma fee schedule at every
|
paper order up to a $400 verified-notional ceiling. The scanner applies each market's Gamma fee schedule at every
|
||||||
consumed ask level and checks the CLOB fee-rate endpoint for a matching enabled
|
consumed ask level and checks the CLOB fee-rate endpoint for a matching enabled
|
||||||
or fee-free state. Any opened position is capped to the exact equal-unit size
|
or fee-free state. Any opened position is capped to the exact equal-unit size
|
||||||
@@ -102,8 +104,12 @@ favorite trends all had 90% upper bounds below zero at 12 hours. A separate
|
|||||||
rules and found zero robust positive rule. Strategy 64 retains online
|
rules and found zero robust positive rule. Strategy 64 retains online
|
||||||
directional evidence under fee policy 2. A separate probation gate can now use
|
directional evidence under fee policy 2. A separate probation gate can now use
|
||||||
capital after at least 12 current-policy independent events produce a net-of-cost
|
capital after at least 12 current-policy independent events produce a net-of-cost
|
||||||
six-hour lower confidence bound above 1% for every required cohort feature. It
|
six-hour lower confidence bound above 1% for every required cohort feature.
|
||||||
uses at most 0.5% of equity per position, 1% per-agent total capital, one new
|
The corresponding 500-market, 1,920-rule chronological audit selected zero
|
||||||
|
rules in validation at 6, 24, or 72 hours. No directional rule is preapproved;
|
||||||
|
probation and full sizing must be earned from new event-deduplicated forward
|
||||||
|
observations. Probation uses at most 0.5% of equity per position, 1% per-agent
|
||||||
|
total capital, one new
|
||||||
position per agent cycle, and one owner per Polymarket event across all agents.
|
position per agent cycle, and one owner per Polymarket event across all agents.
|
||||||
Every probation position exits at the matching six-hour executable bid and keeps
|
Every probation position exits at the matching six-hour executable bid and keeps
|
||||||
the 18% stop policy active. Normal directional sizing remains locked until the
|
the 18% stop policy active. Normal directional sizing remains locked until the
|
||||||
|
|||||||
+19
-2
@@ -1320,6 +1320,15 @@ function compareBundleOpportunities(a,b){
|
|||||||
||Number(b.net_edge||-Infinity)-Number(a.net_edge||-Infinity)
|
||Number(b.net_edge||-Infinity)-Number(a.net_edge||-Infinity)
|
||||||
||Number(b.bundle_net_profit_per_unit||-Infinity)-Number(a.bundle_net_profit_per_unit||-Infinity);
|
||Number(b.bundle_net_profit_per_unit||-Infinity)-Number(a.bundle_net_profit_per_unit||-Infinity);
|
||||||
}
|
}
|
||||||
|
function prioritizeIndependentBundles(candidates,limit=Infinity){
|
||||||
|
const ranked=(candidates||[]).slice().sort(compareBundleOpportunities),firstByEvent=[],alternates=[],seenEvents=new Set();
|
||||||
|
ranked.forEach(candidate=>{
|
||||||
|
const eventKey=bundleEventKey(candidate)||String(candidate.bundle_id||candidate.market_id||"");
|
||||||
|
if(eventKey&&!seenEvents.has(eventKey)){seenEvents.add(eventKey);firstByEvent.push(candidate);}
|
||||||
|
else alternates.push(candidate);
|
||||||
|
});
|
||||||
|
return [...firstByEvent,...alternates].slice(0,Math.max(0,Number(limit)||0));
|
||||||
|
}
|
||||||
function bundleEventExposure(portfolio,eventKey){
|
function bundleEventExposure(portfolio,eventKey){
|
||||||
const key=String(eventKey||"");if(!key)return 0;
|
const key=String(eventKey||"");if(!key)return 0;
|
||||||
return (portfolio&&portfolio.positions||[]).filter(pos=>pos.requires_complete_bundle&&bundleEventKey(pos)===key)
|
return (portfolio&&portfolio.positions||[]).filter(pos=>pos.requires_complete_bundle&&bundleEventKey(pos)===key)
|
||||||
@@ -1367,7 +1376,7 @@ async function fetchBundleFeeRates(tokenIds){
|
|||||||
await Promise.all(workers);return results;
|
await Promise.all(workers);return results;
|
||||||
}
|
}
|
||||||
async function verifyExecutableBundles(candidates){
|
async function verifyExecutableBundles(candidates){
|
||||||
const shortlist=(candidates||[]).slice().sort(compareBundleOpportunities).slice(0,BUNDLE_DEPTH_CANDIDATE_LIMIT);
|
const shortlist=prioritizeIndependentBundles(candidates,BUNDLE_DEPTH_CANDIDATE_LIMIT);
|
||||||
const tokenIds=shortlist.flatMap(candidate=>(candidate.bundle_legs||[]).map(leg=>leg.token_id));
|
const tokenIds=shortlist.flatMap(candidate=>(candidate.bundle_legs||[]).map(leg=>leg.token_id));
|
||||||
const books=await fetchBundleBooks(tokenIds),depthChecked=shortlist.map(candidate=>{
|
const books=await fetchBundleBooks(tokenIds),depthChecked=shortlist.map(candidate=>{
|
||||||
const estimatedCost=Number(candidate.bundle_cost_per_unit),requiredUnits=bundleMinimumExecutionUnits(Math.max(estimatedCost,0.01));
|
const estimatedCost=Number(candidate.bundle_cost_per_unit),requiredUnits=bundleMinimumExecutionUnits(Math.max(estimatedCost,0.01));
|
||||||
@@ -1421,10 +1430,12 @@ async function fetchNegativeRiskBundles(limit=NEG_RISK_EVENT_SCAN_LIMIT){
|
|||||||
const candidates=executableAudit.filter(candidate=>candidate.opportunity_actionable);
|
const candidates=executableAudit.filter(candidate=>candidate.opportunity_actionable);
|
||||||
const seen=new Set();
|
const seen=new Set();
|
||||||
const unique=candidates.filter(candidate=>{const id=String(candidate.bundle_id||candidate.market_id);if(!id||seen.has(id))return false;seen.add(id);return true;});
|
const unique=candidates.filter(candidate=>{const id=String(candidate.bundle_id||candidate.market_id);if(!id||seen.has(id))return false;seen.add(id);return true;});
|
||||||
|
const prioritized=prioritizeIndependentBundles(unique,20);
|
||||||
const closest=executableAudit.find(candidate=>candidate.depth_verified)||executableAudit[0]||null;
|
const closest=executableAudit.find(candidate=>candidate.depth_verified)||executableAudit[0]||null;
|
||||||
return {candidates:unique.slice(0,20),audit:{status:"ok",scanned_at:nowIso(),event_scan_limit:limit,events_scanned:events.length,
|
return {candidates:prioritized,audit:{status:"ok",scanned_at:nowIso(),event_scan_limit:limit,events_scanned:events.length,
|
||||||
evaluated_structures:audited.length,depth_checked_structures:executableAudit.length,depth_verified_structures:executableAudit.filter(candidate=>candidate.depth_verified).length,
|
evaluated_structures:audited.length,depth_checked_structures:executableAudit.length,depth_verified_structures:executableAudit.filter(candidate=>candidate.depth_verified).length,
|
||||||
fee_verified_structures:executableAudit.filter(candidate=>candidate.fees_verified).length,actionable_bundles:unique.length,
|
fee_verified_structures:executableAudit.filter(candidate=>candidate.fees_verified).length,actionable_bundles:unique.length,
|
||||||
|
actionable_events:new Set(unique.map(bundleEventKey).filter(Boolean)).size,returned_events:new Set(prioritized.map(bundleEventKey).filter(Boolean)).size,
|
||||||
closest_margin_cents:closest?+(Number(closest.bundle_net_profit_per_unit)*100).toFixed(2):null,
|
closest_margin_cents:closest?+(Number(closest.bundle_net_profit_per_unit)*100).toFixed(2):null,
|
||||||
closest_return_pct:closest?+(Number(closest.net_edge)*100).toFixed(3):null,
|
closest_return_pct:closest?+(Number(closest.net_edge)*100).toFixed(3):null,
|
||||||
closest_title:closest?closest.question:null,closest_url:closest?closest.url:null}};
|
closest_title:closest?closest.question:null,closest_url:closest?closest.url:null}};
|
||||||
@@ -7215,6 +7226,11 @@ function runEngineSelfTest(){
|
|||||||
Object.assign({},dominanceSuggestion,{bundle_id:"dominance:slow-event:a:b",bundle_event_id:"slow-event",net_edge:0.03,days_to_resolution:30}),
|
Object.assign({},dominanceSuggestion,{bundle_id:"dominance:slow-event:a:b",bundle_event_id:"slow-event",net_edge:0.03,days_to_resolution:30}),
|
||||||
Object.assign({},dominanceSuggestion,{bundle_id:"dominance:fast-event:a:b",bundle_event_id:"fast-event",net_edge:0.02,days_to_resolution:5}),
|
Object.assign({},dominanceSuggestion,{bundle_id:"dominance:fast-event:a:b",bundle_event_id:"fast-event",net_edge:0.02,days_to_resolution:5}),
|
||||||
].sort(compareBundleOpportunities);
|
].sort(compareBundleOpportunities);
|
||||||
|
const independentBundleOrder=prioritizeIndependentBundles([
|
||||||
|
Object.assign({},dominanceSuggestion,{bundle_id:"dominance:event-a:a:b",bundle_event_id:"event-a",net_edge:0.05,days_to_resolution:5}),
|
||||||
|
Object.assign({},dominanceSuggestion,{bundle_id:"dominance:event-a:c:d",bundle_event_id:"event-a",net_edge:0.04,days_to_resolution:5}),
|
||||||
|
Object.assign({},dominanceSuggestion,{bundle_id:"dominance:event-b:a:b",bundle_event_id:"event-b",net_edge:0.02,days_to_resolution:5}),
|
||||||
|
],3);
|
||||||
const eventCapBook=defaultPortfolio();
|
const eventCapBook=defaultPortfolio();
|
||||||
eventCapBook.cash=8800;
|
eventCapBook.cash=8800;
|
||||||
eventCapBook.positions=[
|
eventCapBook.positions=[
|
||||||
@@ -7734,6 +7750,7 @@ function runEngineSelfTest(){
|
|||||||
},
|
},
|
||||||
bundleArbitrage:{
|
bundleArbitrage:{
|
||||||
prioritizesReturnPerLockedDay:capitalEfficiencyOrder[0].bundle_event_id==="fast-event",
|
prioritizesReturnPerLockedDay:capitalEfficiencyOrder[0].bundle_event_id==="fast-event",
|
||||||
|
prioritizesIndependentEventsBeforeAlternates:independentBundleOrder.map(row=>row.bundle_event_id).join(",")==="event-a,event-b,event-a",
|
||||||
derivesLegacyBundleEventKey:bundleEventKey({bundle_id:"dominance:legacy-event:market-a:market-b"})==="legacy-event",
|
derivesLegacyBundleEventKey:bundleEventKey({bundle_id:"dominance:legacy-event:market-a:market-b"})==="legacy-event",
|
||||||
capsUnderlyingEventExposure:eventCapBook.positions.length===2&&eventCapBook.lastDecision.rejectionCounts.bundle_event_cap===1,
|
capsUnderlyingEventExposure:eventCapBook.positions.length===2&&eventCapBook.lastDecision.rejectionCounts.bundle_event_cap===1,
|
||||||
blocksLowReturnPerLockedDay:slowCapitalBook.positions.length===0&&slowCapitalBook.lastDecision.rejectionCounts.bundle_capital_efficiency===1,
|
blocksLowReturnPerLockedDay:slowCapitalBook.positions.length===0&&slowCapitalBook.lastDecision.rejectionCounts.bundle_capital_efficiency===1,
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"strategy": 64,
|
||||||
|
"generated_at": "2026-08-22T12:17:23.498Z",
|
||||||
|
"requested_markets": 500,
|
||||||
|
"fetched_markets": 500,
|
||||||
|
"histories_with_data": 500,
|
||||||
|
"failures": 0,
|
||||||
|
"observations": 6115,
|
||||||
|
"methodology": {
|
||||||
|
"cost_cents": 0.5,
|
||||||
|
"observation_spacing_hours": 12,
|
||||||
|
"split": "60% train / 20% validation / 20% untouched holdout",
|
||||||
|
"cluster_unit": "Polymarket event",
|
||||||
|
"candidate_rules": 1920,
|
||||||
|
"promotion_gate": "Positive event-clustered 90% lower bound with minimum support in train, validation, and holdout"
|
||||||
|
},
|
||||||
|
"probation_rule_ids": [],
|
||||||
|
"durable_rule_ids": [],
|
||||||
|
"horizons": [
|
||||||
|
{"hours": 6, "train_rows": 3640, "validation_rows": 1226, "test_rows": 1223, "validation_selected": 0, "holdout_passed": 0},
|
||||||
|
{"hours": 24, "train_rows": 3482, "validation_rows": 875, "test_rows": 1223, "validation_selected": 0, "holdout_passed": 0},
|
||||||
|
{"hours": 72, "train_rows": 3043, "validation_rows": 215, "test_rows": 1223, "validation_selected": 0, "holdout_passed": 0}
|
||||||
|
],
|
||||||
|
"production_decision": {
|
||||||
|
"preapproved_directional_rules": [],
|
||||||
|
"six_hour_probation_requires_new_forward_evidence": true,
|
||||||
|
"full_directional_promotion_requires_new_forward_evidence": true,
|
||||||
|
"note": "No tested directional rule survived validation at any horizon. This active-market audit can still contain survivorship bias, so it cannot justify relaxing the live evidence gates."
|
||||||
|
},
|
||||||
|
"reproduce": "ADAPTIVE_MARKETS=500 ADAPTIVE_CONCURRENCY=12 npm run evaluate:adaptive"
|
||||||
|
}
|
||||||
@@ -103,7 +103,7 @@ function observations(market, points) {
|
|||||||
}
|
}
|
||||||
if (!complete) continue;
|
if (!complete) continue;
|
||||||
const future = {};
|
const future = {};
|
||||||
for (const hours of [24, 72]) {
|
for (const hours of [6, 24, 72]) {
|
||||||
const next = atOrAfter(points, current.t + hours * HOUR);
|
const next = atOrAfter(points, current.t + hours * HOUR);
|
||||||
if (next && next.t - (current.t + hours * HOUR) <= 3 * HOUR) future[hours] = next.p;
|
if (next && next.t - (current.t + hours * HOUR) <= 3 * HOUR) future[hours] = next.p;
|
||||||
}
|
}
|
||||||
@@ -203,11 +203,13 @@ function evaluateHorizon(horizon) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const compact = (stats) => Object.fromEntries(Object.entries(stats).map(([key, value]) => [key, Number.isFinite(value) ? +value.toFixed(5) : value]));
|
const compact = (stats) => Object.fromEntries(Object.entries(stats).map(([key, value]) => [key, Number.isFinite(value) ? +value.toFixed(5) : value]));
|
||||||
const horizons = [24, 72].map(evaluateHorizon).map((result) => ({ ...result,
|
const horizons = [6, 24, 72].map(evaluateHorizon).map((result) => ({ ...result,
|
||||||
candidates: result.candidates.map((candidate) => ({ rule: candidate.rule, passesHoldout: candidate.passesHoldout,
|
candidates: result.candidates.map((candidate) => ({ rule: candidate.rule, passesHoldout: candidate.passesHoldout,
|
||||||
train: compact(candidate.train), validation: compact(candidate.validation), test: compact(candidate.test) })) }));
|
train: compact(candidate.train), validation: compact(candidate.validation), test: compact(candidate.test) })) }));
|
||||||
const passedByHorizon = horizons.map((result) => new Set(result.candidates.filter((candidate) => candidate.passesHoldout).map((candidate) => candidate.rule.id)));
|
const passedByHorizon = Object.fromEntries(horizons.map((result) => [result.horizon,
|
||||||
const durableRuleIds = [...passedByHorizon[0]].filter((id) => passedByHorizon[1].has(id));
|
new Set(result.candidates.filter((candidate) => candidate.passesHoldout).map((candidate) => candidate.rule.id))]));
|
||||||
|
const probationRuleIds = [...passedByHorizon[6]];
|
||||||
|
const durableRuleIds = [...passedByHorizon[24]].filter((id) => passedByHorizon[72].has(id));
|
||||||
|
|
||||||
console.log(JSON.stringify({ generatedAt: new Date().toISOString(), requestedMarkets: MARKET_LIMIT, fetchedMarkets: markets.length,
|
console.log(JSON.stringify({ generatedAt: new Date().toISOString(), requestedMarkets: MARKET_LIMIT, fetchedMarkets: markets.length,
|
||||||
historiesWithData: histories.filter((result) => result && !result.error && result.points).length,
|
historiesWithData: histories.filter((result) => result && !result.error && result.points).length,
|
||||||
@@ -215,4 +217,4 @@ console.log(JSON.stringify({ generatedAt: new Date().toISOString(), requestedMar
|
|||||||
methodology: { costCents: COST * 100, observationSpacingHours: 12, split: "60% train / 20% validation / 20% untouched holdout",
|
methodology: { costCents: COST * 100, observationSpacingHours: 12, split: "60% train / 20% validation / 20% untouched holdout",
|
||||||
clusterUnit: "Polymarket event", candidateRules: rules.length,
|
clusterUnit: "Polymarket event", candidateRules: rules.length,
|
||||||
promotionGate: "positive event-clustered 90% lower bound with minimum support in train, validation, and holdout" },
|
promotionGate: "positive event-clustered 90% lower bound with minimum support in train, validation, and holdout" },
|
||||||
durableRuleIds, horizons }, null, 2));
|
probationRuleIds, durableRuleIds, horizons }, null, 2));
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ const workflow = fs.readFileSync(new URL("../.github/workflows/autonomous-cycle.
|
|||||||
const runner = fs.readFileSync(new URL("./run-autonomous-cycle.mjs", import.meta.url), "utf8");
|
const runner = fs.readFileSync(new URL("./run-autonomous-cycle.mjs", import.meta.url), "utf8");
|
||||||
const resolutionAudit = JSON.parse(fs.readFileSync(new URL("../research/resolution-week-no-audit.json", import.meta.url), "utf8"));
|
const resolutionAudit = JSON.parse(fs.readFileSync(new URL("../research/resolution-week-no-audit.json", import.meta.url), "utf8"));
|
||||||
const sportsContestAudit = JSON.parse(fs.readFileSync(new URL("../research/sports-contest-no-exploration-audit.json", import.meta.url), "utf8"));
|
const sportsContestAudit = JSON.parse(fs.readFileSync(new URL("../research/sports-contest-no-exploration-audit.json", import.meta.url), "utf8"));
|
||||||
|
const adaptiveAudit = JSON.parse(fs.readFileSync(new URL("../research/adaptive-strategy-64-audit.json", import.meta.url), "utf8"));
|
||||||
const build = Number(index.match(/const BUILD_VERSION = (\d+);/)?.[1]);
|
const build = Number(index.match(/const BUILD_VERSION = (\d+);/)?.[1]);
|
||||||
|
|
||||||
assert.equal(build, 121);
|
assert.equal(build, 121);
|
||||||
@@ -79,6 +80,8 @@ assert.match(index, /const BUNDLE_MAX_VERIFIED_NOTIONAL=400;/);
|
|||||||
assert.match(index, /const BUNDLE_EVENT_CAP_PCT=0\.12;/);
|
assert.match(index, /const BUNDLE_EVENT_CAP_PCT=0\.12;/);
|
||||||
assert.match(index, /const BUNDLE_MIN_DAILY_RETURN=0\.0002;/);
|
assert.match(index, /const BUNDLE_MIN_DAILY_RETURN=0\.0002;/);
|
||||||
assert.match(index, /function compareBundleOpportunities\(a,b\)/);
|
assert.match(index, /function compareBundleOpportunities\(a,b\)/);
|
||||||
|
assert.match(index, /function prioritizeIndependentBundles\(candidates,limit=Infinity\)/);
|
||||||
|
assert.match(index, /prioritizesIndependentEventsBeforeAlternates:/);
|
||||||
assert.match(index, /function bundleEventExposure\(portfolio,eventKey\)/);
|
assert.match(index, /function bundleEventExposure\(portfolio,eventKey\)/);
|
||||||
assert.match(index, /prioritizesReturnPerLockedDay:/);
|
assert.match(index, /prioritizesReturnPerLockedDay:/);
|
||||||
assert.match(index, /capsUnderlyingEventExposure:/);
|
assert.match(index, /capsUnderlyingEventExposure:/);
|
||||||
@@ -108,6 +111,11 @@ assert.ok(sportsContestAudit.corrected_5000_market_result.validation.lower_95 <
|
|||||||
assert.equal(sportsContestAudit.production_constraints.initial_position_pct, 0.5);
|
assert.equal(sportsContestAudit.production_constraints.initial_position_pct, 0.5);
|
||||||
assert.equal(sportsContestAudit.production_constraints.total_lane_cap_pct, 3);
|
assert.equal(sportsContestAudit.production_constraints.total_lane_cap_pct, 3);
|
||||||
assert.equal(sportsContestAudit.production_constraints.exact_entry_fee_required, true);
|
assert.equal(sportsContestAudit.production_constraints.exact_entry_fee_required, true);
|
||||||
|
assert.equal(adaptiveAudit.strategy, 64);
|
||||||
|
assert.equal(adaptiveAudit.fetched_markets, 500);
|
||||||
|
assert.deepEqual(adaptiveAudit.probation_rule_ids, []);
|
||||||
|
assert.deepEqual(adaptiveAudit.durable_rule_ids, []);
|
||||||
|
assert.ok(adaptiveAudit.horizons.every((row) => row.validation_selected === 0 && row.holdout_passed === 0));
|
||||||
assert.match(index, /function sportsContestKey\(m\)/);
|
assert.match(index, /function sportsContestKey\(m\)/);
|
||||||
assert.match(index, /function sportsContestNoSuggestions\(markets\)/);
|
assert.match(index, /function sportsContestNoSuggestions\(markets\)/);
|
||||||
assert.match(index, /const SPORTS_FAVORITE_MAX_NEW_PER_CYCLE=1;/);
|
assert.match(index, /const SPORTS_FAVORITE_MAX_NEW_PER_CYCLE=1;/);
|
||||||
|
|||||||
Reference in New Issue
Block a user