Preserve learning and size verified bundles

This commit is contained in:
Theodore Song
2026-08-21 23:20:09 -04:00
parent 5e4355b850
commit c52368dc9e
8 changed files with 119 additions and 58 deletions
+56 -37
View File
@@ -341,7 +341,7 @@ footer{margin-top:34px;padding-top:22px;border-top:1px solid var(--border);color
<nav class="topnav">
<div class="brand">
<div class="logo">🏆</div>
<div><div class="brand-name">Polymarket Arena</div><div class="brand-sub">10 agents · 5 core + 5 aggressive</div><div class="build-badge">Adaptive strategy 62 · bounded learning state · build 115</div></div>
<div><div class="brand-name">Polymarket Arena</div><div class="brand-sub">10 agents · 5 core + 5 aggressive</div><div class="build-badge">Adaptive strategy 62 · verified-capacity bundles · build 116</div></div>
</div>
<div class="tabs" id="tabs">
<button class="tab" data-tab="overview">Overview</button>
@@ -363,7 +363,7 @@ footer{margin-top:34px;padding-top:22px;border-top:1px solid var(--border);color
<div class="personal-banner" id="personalBanner">
<b>Personal research mode.</b> This copy is for your own analysis, paper tracking, and manual trade research only. It does not pool money, onboard investors, custody funds, bypass eligibility rules, or place orders without your manual approval.
</div>
<div class="live-build-banner"><b>Build 115 active:</b> The public paper agents target five-minute slots with one serialized, self-chained GitHub Actions successor after every successful cycle and cron as recovery. Public forward-learning records retain every field required for future grading, fee-aware returns, cohort calibration, and agent eligibility while dropping duplicated diagnostics, keeping the autonomous state below GitHub's transport ceiling as evidence accumulates. Each fresh cloud browser reconstructs a bounded offline cache from the shared suggestions and open positions, allowing 90-minute cached entries and 24-hour mark-only continuity without persisting private account data; live-depth bundles still require a live connection. Each live cycle scans the 500 most-active eligible markets and 1,000 most-active events, carries exact Gamma fee schedules through cloud and offline caches, and checks complete bundles against live depth. Strategy 62 adds a bounded sports-contest NO exploration lane: one highest-priced NO contract per real contest near the three-day checkpoint, exact entry fee plus slippage, 0.5% initial size, 3% total cap, and automatic forward promotion or suspension. Intact guaranteed bundles are conservatively held at cost in portfolio accounting, while modeled profit remains unbooked until settlement. This point-positive historical pattern is not a proven edge. Phones and computers display the same read-only autonomous state. Profits are not guaranteed.</div>
<div class="live-build-banner"><b>Build 116 active:</b> The public paper agents target five-minute slots with one serialized, self-chained GitHub Actions successor after every successful cycle and cron as recovery. The server preserves oldest-first pending evidence, exact fee schedules, agent promotion scopes, and bundle execution diagnostics from the already-bounded runtime snapshot, so cloud restarts and offline cycles do not silently lose learning context. Each fresh cloud browser reconstructs a bounded offline cache from the shared suggestions and open positions, allowing 90-minute cached entries and 24-hour mark-only continuity without persisting private account data; live-depth bundles still require a live connection. Each live cycle scans the 500 most-active eligible markets and 1,000 most-active events. Complete bundles are repriced across every ask level to the largest equal-leg quantity that remains profitable, depth-covered, fee-verified, and below $400, then portfolio sizing applies the agent's tighter cash and 4% caps. Strategy 62 also keeps the bounded sports-contest NO exploration lane under forward promotion or suspension. Intact guaranteed bundles are conservatively held at cost in portfolio accounting, while modeled profit remains unbooked until settlement. Phones and computers display the same read-only autonomous state. Profits are not guaranteed.</div>
<!-- ============ OVERVIEW ============ -->
<section class="tabpanel" data-tab="overview">
@@ -745,7 +745,7 @@ footer{margin-top:34px;padding-top:22px;border-top:1px solid var(--border);color
</section>
<footer>
Build 115 · Adaptive strategy 62 · Serialized self-chained five-minute slots with cron recovery · Bounded forward-learning transport · Restart-safe offline runtime · Exact-fee directional learning · Conservative intact-bundle accounting · Contest-deduplicated sports exploration · Live depth, fee, and size-verified bundle audit · Corrected one-decision-per-event settlement audit · Autonomous runtime 2 · Offline runtime 3 · Maker research 3 · Agent learning 3 · Paper trading only · Live prices from Polymarket's public Gamma and CLOB APIs · Not financial advice ·
Build 116 · Adaptive strategy 62 · Serialized self-chained five-minute slots with cron recovery · Oldest-first bounded learning transport · Restart-safe offline runtime · Exact-fee directional learning · Verified-capacity complete bundles · Conservative intact-bundle accounting · Contest-deduplicated sports exploration · Corrected one-decision-per-event settlement audit · Autonomous runtime 2 · Offline runtime 3 · Maker research 3 · Agent learning 3 · Paper trading only · Live prices from Polymarket's public Gamma and CLOB APIs · Not financial advice ·
<a class="market-link" href="https://github.com/theodore-song/polymarket-analyst" target="_blank" rel="noopener">Source on GitHub</a>
</footer>
</div>
@@ -774,7 +774,7 @@ const POLITICS_TREND_MIN_HOLD_HOURS = 72;
const EXIT_CONFIRM_HOURS = 6;
const AGENTS_KEY = "pma_agents_v2";
const SUG_KEY = "pma_suggestions_v5";
const BUILD_VERSION = 115;
const BUILD_VERSION = 116;
const AGENT_LEARNING_VERSION = 3;
const SUGGESTION_ENGINE_VERSION = 62;
const MAKER_STRATEGY_VERSION = 3;
@@ -1268,6 +1268,41 @@ function bundleMinimumExecutionUnits(unitCost,baselineUnits=0){
const notionalUnits=Math.ceil(((BUNDLE_MIN_NOTIONAL+0.01)/cost)*100)/100;
return +Math.max(BUNDLE_MIN_UNITS,baseline,notionalUnits).toFixed(2);
}
function bundleQuoteAtUnits(candidate,books,units){
const quantity=+Math.max(0,Number(units)||0).toFixed(2);
const legs=(candidate.bundle_legs||[]).map(leg=>{
const executable=bundleExecutableLeg(books.get(String(leg.token_id||"")),quantity,leg.fee_schedule);
return Object.assign({},leg,{required_units:quantity,ask_vwap:executable?+executable.ask_price.toFixed(6):null,
fee_per_share:executable?+executable.fee_per_share.toFixed(6):null,entry_price:executable?+executable.total_price.toFixed(6):null,
fee_config_valid:Boolean(executable&&executable.fee_config_valid),depth_verified:Boolean(executable)});
});
const depthVerified=quantity>0&&legs.length>=2&&legs.every(leg=>leg.depth_verified);
const cost=depthVerified?legs.reduce((sum,leg)=>sum+Number(leg.entry_price),0):Infinity;
const payout=Number(candidate.bundle_payout_per_unit),profit=payout-cost;
const netReturn=Number.isFinite(cost)&&cost>0?profit/cost:-Infinity;
return {units:quantity,legs,depth_verified:depthVerified,cost,payout,profit,net_return:netReturn,
notional:Number.isFinite(cost)?cost*quantity:Infinity};
}
function bundleQuoteIsActionable(quote){
return Boolean(quote&&quote.depth_verified&&quote.legs.every(leg=>leg.fee_config_valid)
&&quote.profit>=NEG_RISK_MIN_NET_PROFIT&&quote.net_return>=NEG_RISK_MIN_NET_RETURN
&&quote.notional<=BUNDLE_MAX_VERIFIED_NOTIONAL+0.01);
}
function maximizeBundleExecution(candidate,books,minimumUnits){
let best=bundleQuoteAtUnits(candidate,books,minimumUnits);if(!best.depth_verified)return best;
const repricedMinimum=bundleMinimumExecutionUnits(best.cost,minimumUnits);
if(repricedMinimum>best.units)best=bundleQuoteAtUnits(candidate,books,repricedMinimum);
if(!bundleQuoteIsActionable(best))return best;
const maximumUnits=Math.max(best.units,Math.floor((BUNDLE_MAX_VERIFIED_NOTIONAL/Math.max(best.cost,0.01))*100)/100);
const maximumQuote=bundleQuoteAtUnits(candidate,books,maximumUnits);if(bundleQuoteIsActionable(maximumQuote))return maximumQuote;
let low=best.units,high=maximumUnits;
for(let attempt=0;attempt<18&&high-low>=0.02;attempt++){
const midpoint=Math.floor(((low+high)/2)*100)/100;if(midpoint<=low)break;
const quote=bundleQuoteAtUnits(candidate,books,midpoint);
if(bundleQuoteIsActionable(quote)){best=quote;low=midpoint;}else high=midpoint;
}
return best;
}
async function fetchBundleBooks(tokenIds){
const books=new Map(),unique=[...new Set((tokenIds||[]).map(String).filter(Boolean))];
for(let index=0;index<unique.length;index+=BUNDLE_BOOK_BATCH_SIZE){
@@ -1299,41 +1334,13 @@ async function verifyExecutableBundles(candidates){
const tokenIds=shortlist.flatMap(candidate=>(candidate.bundle_legs||[]).map(leg=>leg.token_id));
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 legs=(candidate.bundle_legs||[]).map(leg=>{
const book=books.get(String(leg.token_id||"")),minimum=Number(book&&book.min_order_size||0),units=Math.max(requiredUnits,minimum);
const executable=bundleExecutableLeg(book,units,leg.fee_schedule);
return Object.assign({},leg,{required_units:+units.toFixed(2),ask_vwap:executable?+executable.ask_price.toFixed(6):null,
fee_per_share:executable?+executable.fee_per_share.toFixed(6):null,entry_price:executable?+executable.total_price.toFixed(6):null,
fee_config_valid:Boolean(executable&&executable.fee_config_valid),depth_verified:Boolean(executable)});
});
let commonUnits=Math.max(requiredUnits,...legs.map(leg=>Number(leg.required_units||0)));
let repricedLegs=legs.map(leg=>{
if(Number(leg.required_units)===commonUnits)return leg;
const executable=bundleExecutableLeg(books.get(String(leg.token_id||"")),commonUnits,leg.fee_schedule);
return Object.assign({},leg,{required_units:+commonUnits.toFixed(2),ask_vwap:executable?+executable.ask_price.toFixed(6):null,
fee_per_share:executable?+executable.fee_per_share.toFixed(6):null,entry_price:executable?+executable.total_price.toFixed(6):null,
fee_config_valid:Boolean(executable&&executable.fee_config_valid),depth_verified:Boolean(executable)});
});
let depthVerified=repricedLegs.length>=2&&repricedLegs.every(leg=>leg.depth_verified);
let cost=depthVerified?repricedLegs.reduce((sum,leg)=>sum+Number(leg.entry_price),0):Infinity;
const finalUnits=depthVerified?bundleMinimumExecutionUnits(cost,commonUnits):commonUnits;
if(finalUnits>commonUnits){
commonUnits=finalUnits;
repricedLegs=repricedLegs.map(leg=>{
const executable=bundleExecutableLeg(books.get(String(leg.token_id||"")),commonUnits,leg.fee_schedule);
return Object.assign({},leg,{required_units:+commonUnits.toFixed(2),ask_vwap:executable?+executable.ask_price.toFixed(6):null,
fee_per_share:executable?+executable.fee_per_share.toFixed(6):null,entry_price:executable?+executable.total_price.toFixed(6):null,
fee_config_valid:Boolean(executable&&executable.fee_config_valid),depth_verified:Boolean(executable)});
});
depthVerified=repricedLegs.length>=2&&repricedLegs.every(leg=>leg.depth_verified);
cost=depthVerified?repricedLegs.reduce((sum,leg)=>sum+Number(leg.entry_price),0):Infinity;
}
const payout=Number(candidate.bundle_payout_per_unit),profit=payout-cost,netReturn=Number.isFinite(cost)&&cost>0?profit/cost:-Infinity;
return Object.assign({},candidate,{bundle_legs:repricedLegs,execution_units:+commonUnits.toFixed(2),execution_notional:Number.isFinite(cost)?+(cost*commonUnits).toFixed(2):null,
const minimumUnits=Math.max(requiredUnits,...(candidate.bundle_legs||[]).map(leg=>Number(books.get(String(leg.token_id||""))&&books.get(String(leg.token_id||"")).min_order_size||0)));
const quote=maximizeBundleExecution(candidate,books,minimumUnits),cost=quote.cost,profit=quote.profit,netReturn=quote.net_return;
return Object.assign({},candidate,{bundle_legs:quote.legs,execution_units:quote.units,execution_notional:Number.isFinite(quote.notional)?+quote.notional.toFixed(2):null,
bundle_cost_per_unit:Number.isFinite(cost)?+cost.toFixed(6):null,bundle_net_profit_per_unit:Number.isFinite(profit)?+profit.toFixed(6):null,
edge:Number.isFinite(netReturn)?+netReturn.toFixed(6):null,net_edge:Number.isFinite(netReturn)?+netReturn.toFixed(6):null,
depth_verified:depthVerified,fees_verified:false,trade_ready:false,entry_candidate:false,opportunity_actionable:false,watch_only:true,audited_observation_only:true,
execution_model:"live-order-book-vwap",verification_status:depthVerified?"depth-verified":"insufficient-depth"});
depth_verified:quote.depth_verified,fees_verified:false,trade_ready:false,entry_candidate:false,opportunity_actionable:false,watch_only:true,audited_observation_only:true,
execution_model:"live-order-book-vwap",verification_status:quote.depth_verified?"depth-verified":"insufficient-depth"});
});
const potentiallyActionable=depthChecked.filter(candidate=>candidate.depth_verified
&&Number(candidate.bundle_net_profit_per_unit)>=NEG_RISK_MIN_NET_PROFIT&&Number(candidate.net_edge)>=NEG_RISK_MIN_NET_RETURN
@@ -1435,6 +1442,7 @@ const BUNDLE_DEPTH_CANDIDATE_LIMIT=60;
const BUNDLE_FEE_CONCURRENCY=8;
const BUNDLE_MIN_NOTIONAL=50;
const BUNDLE_MIN_UNITS=5;
const BUNDLE_MAX_VERIFIED_NOTIONAL=400;
const SPORTS_FAVORITE_MIN_ENTRY=0.03;
const SPORTS_FAVORITE_MAX_ENTRY=0.97;
const SPORTS_FAVORITE_TARGET_LEAD_HOURS=72;
@@ -6949,6 +6957,13 @@ function runEngineSelfTest(){
{id:"zero-c",question:"C wins",outcomes:'["Yes","No"]',outcomePrices:'["0.335","0.665"]',clobTokenIds:'["zc-yes","zc-no"]',bestBid:0.33,bestAsk:0.34,feesEnabled:false,liquidityNum:30000,acceptingOrders:true},
]});
const depthVwapFixture=bundleExecutableAsk({asks:[{price:"0.40",size:"30"},{price:"0.39",size:"20"}]},50);
const scalableBundlePrices=[0.30,0.31,0.34];
const scalableBundleBooks=new Map((zeroFeeBundleSuggestion.bundle_legs||[]).map((leg,index)=>[String(leg.token_id),
{min_order_size:"5",asks:[{price:String(scalableBundlePrices[index]),size:"500"}]}]));
const scalableBundleQuote=maximizeBundleExecution(zeroFeeBundleSuggestion,scalableBundleBooks,bundleMinimumExecutionUnits(0.95));
const depthLimitedBundleBooks=new Map((zeroFeeBundleSuggestion.bundle_legs||[]).map((leg,index)=>[String(leg.token_id),
{min_order_size:"5",asks:[{price:String(scalableBundlePrices[index]),size:String(index===2?120:500)}]}]));
const depthLimitedBundleQuote=maximizeBundleExecution(zeroFeeBundleSuggestion,depthLimitedBundleBooks,bundleMinimumExecutionUnits(0.95));
const tinyReturnBundle=negativeRiskBundleSuggestion({id:"bundle-tiny",title:"Ten-way result",slug:"bundle-tiny",negRisk:true,enableNegRisk:true,markets:Array.from({length:10},(_,i)=>({
id:`bundle-tiny-${i}`,question:`Outcome ${i+1}`,outcomes:'["Yes","No"]',outcomePrices:'["0.1055","0.8945"]',clobTokenIds:`["tiny-${i}-yes","tiny-${i}-no"]`,
bestBid:0.1055,bestAsk:0.1065,liquidityNum:30000,volumeNum:100000,volume24hr:10000,acceptingOrders:true,
@@ -7491,6 +7506,10 @@ function runEngineSelfTest(){
&&zeroFeeBundleSuggestion.bundle_cost_per_unit===0.95&&zeroFeeBundleSuggestion.bundle_net_profit_per_unit===0.05),
appliesPublishedFeeCurve:bundleFeePerShare({rate:0.07,exponent:1,takerOnly:true},0.5)===0.0175,
depthVwapConsumesMultipleAskLevels:depthVwapFixture===0.396,
sizesToLargestVerifiedProfitableFill:scalableBundleQuote.units===421.05&&Math.abs(scalableBundleQuote.notional-399.9975)<0.0001
&&scalableBundleQuote.net_return>0.05,
stopsSizingAtShallowestBundleLeg:depthLimitedBundleQuote.units>=119.9&&depthLimitedBundleQuote.units<=120
&&depthLimitedBundleQuote.notional<=BUNDLE_MAX_VERIFIED_NOTIONAL,
liveRepricingRoundsUpToMinimumNotional:repricedBoundaryUnits===50.21&&repricedBoundaryUnits*0.996041>=BUNDLE_MIN_NOTIONAL+0.009,
repricedMinimumNotionalOpensAtomically:Boolean(repricedBoundaryOpen&&repricedBoundaryBook.positions.length===2
&&repricedBoundaryOpen.cost>=BUNDLE_MIN_NOTIONAL),