@@ -341,7 +341,7 @@ footer{margin-top:34px;padding-top:22px;border-top:1px solid var(--border);color
< nav class = "topnav" >
< nav class = "topnav" >
< div class = "brand" >
< div class = "brand" >
< div class = "logo" > 🏆< / div >
< 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 50 · build 59 < / 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 51 · build 62 < / div > < / div >
< / div >
< / div >
< div class = "tabs" id = "tabs" >
< div class = "tabs" id = "tabs" >
< button class = "tab" data-tab = "overview" > Overview< / button >
< 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" >
< 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.
< 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 >
< div class = "live-build-banner" > < b > Build 61 active:< / b > unproven directional signals train the event-clustered learner without risking cash. New observations prioritize under-sampled strategy cohorts and independent events before repeats, while shared state normalizes and fails over across configured Neon URLs . Cloud provider failures remain visible after every completed cycle instead of being mistaken for a successful cross-device save. Cohorts can trade only after positive promotion . Live-priced complete YES or NO negative-risk bundles may trade when their worst-case payout remains positive after estimated costs; cached bundle prices never open positions. This remains paper trading; profits are not guaranteed.< / div >
< div class = "live-build-banner" > < b > Build 62 active:< / b > unproven directional signals train the event-clustered learner without risking cash. Promotion now requires separate positive 24-hour and 72-hour net-of-cost evidence from independent events under the current str ategy; missed grading windows expire instead of being mislabeled . Cloud provider failures remain visible after every completed cycle. Live-priced complete YES or NO negative-risk bundles may trade when their worst-case payout remains positive after estimated costs; cached bundle prices never open positions. This remains paper trading; profits are not guaranteed.< / div >
<!-- ============ OVERVIEW ============ -->
<!-- ============ OVERVIEW ============ -->
< section class = "tabpanel" data-tab = "overview" >
< section class = "tabpanel" data-tab = "overview" >
@@ -378,11 +378,11 @@ footer{margin-top:34px;padding-top:22px;border-top:1px solid var(--border);color
< g fill = "#d9b4ff" > < circle cx = "380" cy = "40" r = "6" / > < / g >
< g fill = "#d9b4ff" > < circle cx = "380" cy = "40" r = "6" / > < / g >
< / svg >
< / svg >
< h1 > Ten AI agents race to < span class = "grad" > beat the market< / span > < / h1 >
< h1 > Ten AI agents race to < span class = "grad" > beat the market< / span > < / h1 >
< p > Each cycle loads the 500 most active Polymarket markets, then requires direction to agree across independent time windows before liquidity, evidence, timing, and friction checks can make an idea trade-ready.< / p >
< p > Each cycle loads the 500 most active eligible Yes/No Polymarket markets, then requires direction to agree across independent time windows before liquidity, evidence, timing, and friction checks can make an idea trade-ready.< / p >
< div class = "badges" >
< div class = "badges" >
< span class = "hbadge" > 🏆 10 competing agents< / span >
< span class = "hbadge" > 🏆 10 competing agents< / span >
< span class = "hbadge" > 5 aggressive strategies< / span >
< span class = "hbadge" > 5 aggressive strategies< / span >
< span class = "hbadge" > Top 500 active markets< / span >
< span class = "hbadge" > Top 500 eligible Yes/No markets< / span >
< span class = "hbadge" > Ranked by activity + confirmation< / span >
< span class = "hbadge" > Ranked by activity + confirmation< / span >
< span class = "hbadge" > Live Polymarket data< / span >
< span class = "hbadge" > Live Polymarket data< / span >
< / div >
< / div >
@@ -719,7 +719,7 @@ footer{margin-top:34px;padding-top:22px;border-top:1px solid var(--border);color
< div class = "card" style = "margin-top:16px" >
< div class = "card" style = "margin-top:16px" >
< div class = "card-h" > < h3 > The live cycle< / h3 > < / div >
< div class = "card-h" > < h3 > The live cycle< / h3 > < / div >
< ol class = "steps" >
< ol class = "steps" >
< li > < b > Fetch< / b > — load the 500 most active Polymarket markets and tag each by category.< / li >
< li > < b > Fetch< / b > — load the 500 most active eligible Yes/No Polymarket markets and tag each by category.< / li >
< li > < b > Score< / b > — rank those active markets 0– 100 by conviction and estimate edge vs. a fair-value model.< / li >
< li > < b > Score< / b > — rank those active markets 0– 100 by conviction and estimate edge vs. a fair-value model.< / li >
< li > < b > Suggest< / b > — surface the strongest picks per category with a plain-English rationale.< / li >
< li > < b > Suggest< / b > — surface the strongest picks per category with a plain-English rationale.< / li >
< li > < b > Compete< / b > — the strategy agents trade the same suggestions their own way, stop-loss weak positions, scale out through gain-stop tiers, exit stale or fading trades, then snapshot equity.< / li >
< li > < b > Compete< / b > — the strategy agents trade the same suggestions their own way, stop-loss weak positions, scale out through gain-stop tiers, exit stale or fading trades, then snapshot equity.< / li >
@@ -745,7 +745,7 @@ footer{margin-top:34px;padding-top:22px;border-top:1px solid var(--border);color
< / section >
< / section >
< footer >
< footer >
Build 61 · Adaptive strategy 50 · Paper trading only · Live prices from Polymarket's public Gamma API · Not financial advice ·
Build 62 · Adaptive strategy 51 · Paper trading only · Live prices from Polymarket's public Gamma API · Not financial advice ·
< a class = "market-link" href = "https://github.com/theodore-song/polymarket-analyst" target = "_blank" rel = "noopener" > Source on GitHub< / a >
< a class = "market-link" href = "https://github.com/theodore-song/polymarket-analyst" target = "_blank" rel = "noopener" > Source on GitHub< / a >
< / footer >
< / footer >
< / div >
< / div >
@@ -774,9 +774,9 @@ const POLITICS_TREND_MIN_HOLD_HOURS = 72;
const EXIT_CONFIRM_HOURS = 6;
const EXIT_CONFIRM_HOURS = 6;
const AGENTS_KEY = "pma_agents_v2";
const AGENTS_KEY = "pma_agents_v2";
const SUG_KEY = "pma_suggestions_v5";
const SUG_KEY = "pma_suggestions_v5";
const BUILD_VERSION = 61 ;
const BUILD_VERSION = 62 ;
const SUGGESTION_ENGINE_VERSION = 50 ;
const SUGGESTION_ENGINE_VERSION = 51 ;
const PREVIOUS_STRATEGY_VERSION = 49 ;
const PREVIOUS_STRATEGY_VERSION = 50 ;
const LEGACY_BUILD_STRATEGY_LINEAGE = Object.freeze({40:40,41:40});
const LEGACY_BUILD_STRATEGY_LINEAGE = Object.freeze({40:40,41:40});
function normalizedStrategyVersion(value){
function normalizedStrategyVersion(value){
const version=Number(value||0);
const version=Number(value||0);
@@ -923,10 +923,12 @@ const OFFLINE_ENTRY_MAX_AGE_MS = 90*60*1000;
const OFFLINE_CACHE_MAX_AGE_MS = 24*60*60*1000;
const OFFLINE_CACHE_MAX_AGE_MS = 24*60*60*1000;
const NETWORK_REQUEST_TIMEOUT_MS = 8000;
const NETWORK_REQUEST_TIMEOUT_MS = 8000;
const PRICE_REQUEST_TIMEOUT_MS = 4000;
const PRICE_REQUEST_TIMEOUT_MS = 4000;
const SIGNAL_EVAL_HOURS = 24 ;
const SIGNAL_EVAL_HORIZONS = Object.freeze([24,72]) ;
const SIGNAL_EVAL_TOLERANCE_HOURS = 6;
const SIGNAL_EVAL_HOURS = SIGNAL_EVAL_HORIZONS[0];
const SIGNAL_LEDGER_PENDING_LIMIT = 300;
const SIGNAL_LEDGER_PENDING_LIMIT = 300;
const SIGNAL_LEDGER_OUTCOME_LIMIT = 500;
const SIGNAL_LEDGER_OUTCOME_LIMIT = 500;
const SIGNAL_LEDGER_RETRY_HOURS = 168 ;
const SIGNAL_LEDGER_RETRY_HOURS = SIGNAL_EVAL_HORIZONS[SIGNAL_EVAL_HORIZONS.length-1]+SIGNAL_EVAL_TOLERANCE_HOURS ;
const SIGNAL_LEDGER_DUE_FETCH_LIMIT = 80;
const SIGNAL_LEDGER_DUE_FETCH_LIMIT = 80;
const currentCycleHour = () => {const p=partsInLocalTime();return `${p.year}-${p.month}-${p.day}T${p.hour}:${p.minute}|s${SUGGESTION_ENGINE_VERSION}`;};
const currentCycleHour = () => {const p=partsInLocalTime();return `${p.year}-${p.month}-${p.day}T${p.hour}:${p.minute}|s${SUGGESTION_ENGINE_VERSION}`;};
function cycleHourFromIso(iso){
function cycleHourFromIso(iso){
@@ -975,6 +977,10 @@ async function mapWithConcurrency(items,limit,mapper){
function parseJsonField(v){if(v==null)return [];if(Array.isArray(v))return v;try{return JSON.parse(v);}catch(e){return [];}}
function parseJsonField(v){if(v==null)return [];if(Array.isArray(v))return v;try{return JSON.parse(v);}catch(e){return [];}}
function toNum(v,d=0){const n=Number(v);return Number.isFinite(n)?n:d;}
function toNum(v,d=0){const n=Number(v);return Number.isFinite(n)?n:d;}
function daysUntil(iso){if(!iso)return null;const dt=new Date(iso);if(isNaN(dt))return null;return (dt-new Date())/86400000;}
function daysUntil(iso){if(!iso)return null;const dt=new Date(iso);if(isNaN(dt))return null;return (dt-new Date())/86400000;}
function hasYesNoOutcomes(raw){
const labels=parseJsonField(raw&&raw.outcomes).map(outcome=>String(outcome||"").trim().toLowerCase());
return labels.length===2&&labels[0]==="yes"&&labels[1]==="no";
}
const CATEGORY_RULES=[
const CATEGORY_RULES=[
["Politics",["politics","election","elections","us-politics","geopolitics","trump","world-leaders","government","congress","policy","biden","2026-election","democrats","republicans"]],
["Politics",["politics","election","elections","us-politics","geopolitics","trump","world-leaders","government","congress","policy","biden","2026-election","democrats","republicans"]],
["Crypto",["crypto","bitcoin","ethereum","btc","eth","solana","memecoins","defi","stablecoin","xrp"]],
["Crypto",["crypto","bitcoin","ethereum","btc","eth","solana","memecoins","defi","stablecoin","xrp"]],
@@ -990,7 +996,7 @@ function classifyCategory(tags){
function normalizeMarket(raw,{allowClosed=false}={}){
function normalizeMarket(raw,{allowClosed=false}={}){
const outcomes=parseJsonField(raw.outcomes);
const outcomes=parseJsonField(raw.outcomes);
const prices=parseJsonField(raw.outcomePrices).map(p=>toNum(p));
const prices=parseJsonField(raw.outcomePrices).map(p=>toNum(p));
if(outcomes.length!==2 ||prices.length!==2)return null;
if(!hasYesNoOutcomes(raw) ||prices.length!==2)return null;
if(!allowClosed& & (raw.acceptingOrders===false||raw.closed))return null;
if(!allowClosed& & (raw.acceptingOrders===false||raw.closed))return null;
const yes=prices[0];
const yes=prices[0];
if(!Number.isFinite(yes)||yes< 0 | | yes > 1||(!allowClosed& & (yes< =0||yes>=1)))return null;
if(!Number.isFinite(yes)||yes< 0 | | yes > 1||(!allowClosed& & (yes< =0||yes>=1)))return null;
@@ -1009,8 +1015,8 @@ function normalizeMarket(raw,{allowClosed=false}={}){
closed:Boolean(raw.closed),accepting_orders:raw.acceptingOrders!==false,
closed:Boolean(raw.closed),accepting_orders:raw.acceptingOrders!==false,
url:ev.slug?`https://polymarket.com/event/${ev.slug}`:""};
url:ev.slug?`https://polymarket.com/event/${ev.slug}`:""};
}
}
async function fetchMarkets(pages=Infinity,perPage=100,onProgress=null){
async function fetchMarkets(pages=Infinity,perPage=100,onProgress=null,eligibleLimit=null ){
const all=[];
const all=[],eligible=[] ;
const maxPages=Number.isFinite(pages)?pages:MAX_ACTIVE_MARKET_PAGES;
const maxPages=Number.isFinite(pages)?pages:MAX_ACTIVE_MARKET_PAGES;
const seen=new Set();
const seen=new Set();
const useKeyset=!Number.isFinite(pages)||pages>20;
const useKeyset=!Number.isFinite(pages)||pages>20;
@@ -1034,12 +1040,14 @@ async function fetchMarkets(pages=Infinity,perPage=100,onProgress=null){
if(id&&seen.has(id))continue;
if(id&&seen.has(id))continue;
if(id)seen.add(id);
if(id)seen.add(id);
all.push(m);added++;
all.push(m);added++;
const normalized=normalizeMarket(m);
if(normalized&&normalized.question)eligible.push(normalized);
}
}
if(useKeyset)cursor=page.next_cursor||null;
if(useKeyset)cursor=page.next_cursor||null;
if(onProgress)onProgress(all.length);
if(onProgress)onProgress(eligible.length, all.length);
if(raw.length < perPage | | added = ==0||(useKeyset&&!cursor))break;
if((eligibleLimit &&eligible.length>=eligibleLimit)||raw.length<perPage||added= ==0||(useKeyset&&!cursor))break;
}
}
return all.map(normalizeMarket).filter(m=>m &&m.question);
return eligibleLimit?eligible.slice(0,eligibleLimit):eligible;
}
}
async function fetchMarketPrice(id){
async function fetchMarketPrice(id){
try{const r=await fetchWithTimeout(`${GAMMA}/markets/${id}`,{},PRICE_REQUEST_TIMEOUT_MS);if(!r.ok)return null;return normalizeMarket(await r.json(),{allowClosed:true});}
try{const r=await fetchWithTimeout(`${GAMMA}/markets/${id}`,{},PRICE_REQUEST_TIMEOUT_MS);if(!r.ok)return null;return normalizeMarket(await r.json(),{allowClosed:true});}
@@ -1051,12 +1059,13 @@ function negativeRiskBundleSuggestion(event){
if(rawLegs.length< 2 | | rawLegs . some ( m = > m.closed||m.active===false||m.acceptingOrders===false))return null ;
if(rawLegs.length< 2 | | rawLegs . some ( m = > m.closed||m.active===false||m.acceptingOrders===false))return null ;
const eventTags=Array.isArray(event.tags)?event.tags:[],category=classifyCategory(eventTags);
const eventTags=Array.isArray(event.tags)?event.tags:[],category=classifyCategory(eventTags);
const quotes=rawLegs.map(raw=>{
const quotes=rawLegs.map(raw=>{
const outcomes=parseJsonField(raw.outcomes).map(outcome=>String(outcome||"").trim().toLowerCase());
const prices=parseJsonField(raw.outcomePrices).map(toNum),tokens=parseJsonField(raw.clobTokenIds).map(String);
const prices=parseJsonField(raw.outcomePrices).map(toNum),tokens=parseJsonField(raw.clobTokenIds).map(String);
return {market_id:String(raw.id||""),question:(raw.question||"").trim(),yes_bid:toNum(raw.bestBid,NaN),yes_ask:toNum(raw.bestAsk,NaN),
return {market_id:String(raw.id||""),question:(raw.question||"").trim(),yes_bid:toNum(raw.bestBid,NaN),yes_ask:toNum(raw.bestAsk,NaN),
yes_mid:prices[0],no_mid:prices[1],yes_token:tokens[0]||null,no_token:tokens[1]||null,
yes_mid:prices[0],no_mid:prices[1],yes_token:tokens[0]||null,no_token:tokens[1]||null,
liquidity:toNum(raw.liquidityNum||raw.liquidity),url:event.slug?`https://polymarket.com/event/${event.slug}`:""};
binary_labels:outcomes[0]==="yes" &&outcomes[1]==="no", liquidity:toNum(raw.liquidityNum||raw.liquidity),url:event.slug?`https://polymarket.com/event/${event.slug}`:""};
});
});
if(quotes.some(leg=>!leg.market_id||!leg.yes_token||!leg.no_token||!Number.isFinite(leg.yes_bid)||!Number.isFinite(leg.yes_ask)
if(quotes.some(leg=>!leg.binary_labels||!leg. market_id||!leg.yes_token||!leg.no_token||!Number.isFinite(leg.yes_bid)||!Number.isFinite(leg.yes_ask)
||leg.yes_bid< 0 | | leg . yes_ask > 1||leg.yes_ask< leg.yes_bid | | ! Number . isFinite ( leg . yes_mid ) | | ! Number . isFinite ( leg . no_mid )
||leg.yes_bid< 0 | | leg . yes_ask > 1||leg.yes_ask< leg.yes_bid | | ! Number . isFinite ( leg . yes_mid ) | | ! Number . isFinite ( leg . no_mid )
||leg.liquidity< NEG_RISK_MIN_LIQUIDITY ) ) return null ;
||leg.liquidity< NEG_RISK_MIN_LIQUIDITY ) ) return null ;
const makeCandidate=(side)=>{
const makeCandidate=(side)=>{
@@ -1749,7 +1758,7 @@ function summarizeLearningBucket(bucket,shrinkage){
const pooledVariance=(priorWeight*priorVariance+weight*variance)/(priorWeight+weight||1);
const pooledVariance=(priorWeight*priorVariance+weight*variance)/(priorWeight+weight||1);
const stderr=Math.sqrt(pooledVariance/Math.max(1,weight));
const stderr=Math.sqrt(pooledVariance/Math.max(1,weight));
const score=Number(bucket&&bucket.sum||0)/(weight+shrinkage);
const score=Number(bucket&&bucket.sum||0)/(weight+shrinkage);
return {samples:Number(bucket& & bucket.count||0),observations:Number(bucket& & bucket.observations||bucket& & bucket.count||0),weight:+weight.toFixed(2),raw:+raw.toFixed(4),
return {samples:Number(bucket& & bucket.count||0),observations:Number(bucket& & bucket.observations||bucket& & bucket.count||0),weight:+weight.toFixed(2),current_weight:+Number(bucket & & bucket.currentWeight||0).toFixed(2), raw:+raw.toFixed(4),
score:+score.toFixed(4),stderr:+stderr.toFixed(4),lower_bound:+(score-1.28*stderr).toFixed(4),
score:+score.toFixed(4),stderr:+stderr.toFixed(4),lower_bound:+(score-1.28*stderr).toFixed(4),
upper_bound:+(score+1.28*stderr).toFixed(4),win_rate:weight?Number(bucket.wins||0)/weight:0};
upper_bound:+(score+1.28*stderr).toFixed(4),win_rate:weight?Number(bucket.wins||0)/weight:0};
}
}
@@ -1771,10 +1780,17 @@ function prioritizeSignalObservations(suggestions,ledger,pending=[]){
||(Number(b.s.conviction||0)-Number(a.s.conviction||0))||(a.index-b.index))
||(Number(b.s.conviction||0)-Number(a.s.conviction||0))||(a.index-b.index))
.map(row=>row.s);
.map(row=>row.s);
}
}
function signalGradedHorizons(item){
return new Set((Array.isArray(item&&item.graded_horizons)?item.graded_horizons:[]).map(Number).filter(Number.isFinite));
}
function signalDueHorizon(item,ageHours){
const graded=signalGradedHorizons(item);
return SIGNAL_EVAL_HORIZONS.find(horizon=>!graded.has(horizon)&&ageHours>=horizon&&ageHours<=horizon+SIGNAL_EVAL_TOLERANCE_HOURS)||null;
}
function pendingSignalMarketIds(ledger,knownIds=new Set(),now=Date.now()){
function pendingSignalMarketIds(ledger,knownIds=new Set(),now=Date.now()){
const rows=((ledger& & ledger.pending)||[]).map(item=>({item,started:new Date(item.observed_at||0).getTime()}))
const rows=((ledger& & ledger.pending)||[]).map(item=>({item,started:new Date(item.observed_at||0).getTime()}))
.filter(row=>Number.isFinite(row.started))
.filter(row=>Number.isFinite(row.started))
.filter(row=>{const age=(now-row.started)/3600000;return age>=SIGNAL_EVAL_HOURS &&age<=SIGNAL_LEDGER_RETRY_HOURS; } )
.filter(row=>signalDueHorizon(row.item,(now-row.started)/3600000)!=null )
.sort((a,b)=>a.started-b.started);
.sort((a,b)=>a.started-b.started);
const ids=[],seen=new Set();
const ids=[],seen=new Set();
for(const {item} of rows){
for(const {item} of rows){
@@ -1791,15 +1807,22 @@ function updateSignalLedger(st,markets,suggestions){
const now=Date.now(),marketMap=Object.fromEntries((markets||[]).map(m=>[String(m.id),m])),stillPending=[];
const now=Date.now(),marketMap=Object.fromEntries((markets||[]).map(m=>[String(m.id),m])),stillPending=[];
for(const item of ledger.pending){
for(const item of ledger.pending){
const started=new Date(item.observed_at||0).getTime(),ageHours=Number.isFinite(started)?(now-started)/3600000:Infinity;
const started=new Date(item.observed_at||0).getTime(),ageHours=Number.isFinite(started)?(now-started)/3600000:Infinity;
const graded=signalGradedHorizons(item),dueHorizon=signalDueHorizon(item,ageHours);
const fresh=marketMap[String(item.market_id)],future=signalPrice(fresh,item.side);
const fresh=marketMap[String(item.market_id)],future=signalPrice(fresh,item.side);
if(ag eHours>=SIGNAL_EVAL_HOURS & & Number.isFinite(future)& & future>=0& & future< =1){
if(du eHorizon!=null & & Number.isFinite(future)& & future>=0& & future< =1){
const entry=Math.max(0.01,Number(item.entry_price||0.01));
const entry=Math.max(0.01,Number(item.entry_price||0.01));
const gross=future/entry-1,estimatedCost=SIGNAL_ROUND_TRIP_COST/entry;
const gross=future/entry-1,estimatedCost=SIGNAL_ROUND_TRIP_COST/entry;
const outcome=clamp(gross-estimatedCost,-1,2);
const outcome=clamp(gross-estimatedCost,-1,2);
ledger.outcomes.push(Object.assign({},item,{evaluated_at:nowIso(),horizon_hours:+ageHours.toFixed(1),future_price:+future.toFixed(4),
graded.add(dueHorizon);
ledger.outcomes.push(Object.assign({},item,{graded_horizons:undefined,evaluated_at:nowIso(),target_horizon_hours:dueHorizon,horizon_hours:+ageHours.toFixed(1),future_price:+future.toFixed(4),
gross_return:+gross.toFixed(4),estimated_cost_return:+estimatedCost.toFixed(4),return:+outcome.toFixed(4)}));
gross_return:+gross.toFixed(4),estimated_cost_return:+estimatedCost.toFixed(4),return:+outcome.toFixed(4)}));
}else if(ageHours < =SIGNAL_LEDGER_RETRY_HOURS)stillPending.push(item);
}
else ledger.expired_ungraded=Number(ledger.expired_ungraded||0)+1;
const remaining=SIGNAL_EVAL_HORIZONS.filter(horizon=>!graded.has(horizon)&&ageHours<=horizon+SIGNAL_EVAL_TOLERANCE_HOURS);
if(remaining.length)stillPending.push(Object.assign({},item,{graded_horizons:[...graded].sort((a,b)=>a-b)}));
else{
const missed=SIGNAL_EVAL_HORIZONS.filter(horizon=>!graded.has(horizon)).length;
if(missed)ledger.expired_ungraded=Number(ledger.expired_ungraded||0)+missed;
}
}
}
stillPending.sort((a,b)=>new Date(a.observed_at||0)-new Date(b.observed_at||0));
stillPending.sort((a,b)=>new Date(a.observed_at||0)-new Date(b.observed_at||0));
const existing=new Set(stillPending.map(x=>x.key)),pendingPairs=new Set(stillPending.map(x=>`${x.market_id}:${x.side}`));
const existing=new Set(stillPending.map(x=>x.key)),pendingPairs=new Set(stillPending.map(x=>`${x.market_id}:${x.side}`));
@@ -1809,7 +1832,7 @@ function updateSignalLedger(st,markets,suggestions){
for(const s of observable){
for(const s of observable){
const pair=`${s.market_id}:${s.side}`,key=`${pair}:${bucket}`;if(existing.has(key)||pendingPairs.has(pair))continue;
const pair=`${s.market_id}:${s.side}`,key=`${pair}:${bucket}`;if(existing.has(key)||pendingPairs.has(pair))continue;
if(stillPending.length>=SIGNAL_LEDGER_PENDING_LIMIT)break;
if(stillPending.length>=SIGNAL_LEDGER_PENDING_LIMIT)break;
existing.add(key);pendingPairs.add(pair);stillPending.push({key,market_id:String(s.market_id),event_key:String(s.url||s.event||s.market_id),observed_at:nowIso(),side:s.side,entry_price:Number(s.entry_price),
existing.add(key);pendingPairs.add(pair);stillPending.push({key,market_id:String(s.market_id),event_key:String(s.url||s.event||s.market_id),observed_at:nowIso(),graded_horizons:[], side:s.side,entry_price:Number(s.entry_price),
signal_type:s.signal_type||"unknown",quality:s.quality||"unknown",category:s.category||"Other",conviction:Number(s.conviction||0),
signal_type:s.signal_type||"unknown",quality:s.quality||"unknown",category:s.category||"Other",conviction:Number(s.conviction||0),
days_to_resolution:s.days_to_resolution,trade_ready_at_observation:Boolean(s.trade_ready),
days_to_resolution:s.days_to_resolution,trade_ready_at_observation:Boolean(s.trade_ready),
strategy_version:SUGGESTION_ENGINE_VERSION,build_version:BUILD_VERSION});
strategy_version:SUGGESTION_ENGINE_VERSION,build_version:BUILD_VERSION});
@@ -1827,17 +1850,21 @@ function buildSignalCalibration(ledger){
const ret=clamp(Number(outcome.return||0),-1,2);if(!Number.isFinite(ret)||weight< =0)return;
const ret=clamp(Number(outcome.return||0),-1,2);if(!Number.isFinite(ret)||weight< =0)return;
const marketId=String(outcome.market_id||`unidentified-observation-${index}`);
const marketId=String(outcome.market_id||`unidentified-observation-${index}`);
const clusterId=String(outcome.event_key||outcome.event||marketId).trim().toLowerCase()||marketId;
const clusterId=String(outcome.event_key||outcome.event||marketId).trim().toLowerCase()||marketId;
learningFeatures(outcome).forEach(key=>{
const horizon=Number(outcome.target_horizon_hours),baseFeatures= learningFeatures(outcome);
const byEvent=clusters[key]||(clusters[key]={}),cluster=byEvent[clusterId]||(byEvent[clusterId]={weight:0,sum:0,observations:0}) ;
const featureKeys=SIGNAL_EVAL_HORIZONS.includes(horizon)?[...baseFeatures,...baseFeatures.map(key=>`${key}|horizon:${horizon}`)]:baseFeatures ;
cluster.weight+=weight;cluster.sum+=ret*weight;cluster.observations++;
featureKeys.forEach(key=>{
const byEvent=clusters[key]||(clusters[key]={}),cluster=byEvent[clusterId]||(byEvent[clusterId]={weight:0,currentWeight:0,sum:0,observations:0});
cluster.weight+=weight;if(version===SUGGESTION_ENGINE_VERSION)cluster.currentWeight+=weight;
cluster.sum+=ret*weight;cluster.observations++;
});
});
});
});
const buckets={};
const buckets={};
Object.entries(clusters).forEach(([key,byEvent])=>{
Object.entries(clusters).forEach(([key,byEvent])=>{
const b=buckets[key]={weight:0,sum:0,sumSq:0,wins:0,count:0,observations:0};
const b=buckets[key]={weight:0,currentWeight:0, sum:0,sumSq:0,wins:0,count:0,observations:0};
Object.values(byEvent).forEach(cluster=>{
Object.values(byEvent).forEach(cluster=>{
const clusterWeight=Math.min(1,Number(cluster.weight||0)),ret=Number(cluster.sum||0)/Math.max(0.0001,Number(cluster.weight||0));
const clusterWeight=Math.min(1,Number(cluster.weight||0)),ret=Number(cluster.sum||0)/Math.max(0.0001,Number(cluster.weight||0));
b.weight+=clusterWeight;b.sum+=ret*clusterWeight;b.sumSq+=ret*ret*clusterWeight;b.wins+=(ret>0?clusterWeight:0);
b.weight+=clusterWeight;b.sum+=ret*clusterWeight;b.sumSq+=ret*ret*clusterWeight;b.wins+=(ret>0?clusterWeight:0);
b.currentWeight+=Math.min(clusterWeight,Number(cluster.currentWeight||0));
b.count++;b.observations+=Number(cluster.observations||0);
b.count++;b.observations+=Number(cluster.observations||0);
});
});
});
});
@@ -1850,21 +1877,24 @@ function buildSignalCalibration(ledger){
const currentEvents=new Set(currentOutcomes.map((outcome,index)=>String(outcome.event_key||outcome.event||outcome.market_id||`unidentified-current-${index}`).trim().toLowerCase()));
const currentEvents=new Set(currentOutcomes.map((outcome,index)=>String(outcome.event_key||outcome.event||outcome.market_id||`unidentified-current-${index}`).trim().toLowerCase()));
return {version:SUGGESTION_ENGINE_VERSION,samples:outcomes.length,markets:identifiedMarkets.size,events:identifiedEvents.size,
return {version:SUGGESTION_ENGINE_VERSION,samples:outcomes.length,markets:identifiedMarkets.size,events:identifiedEvents.size,
current_samples:currentOutcomes.length,current_markets:currentMarkets.size,current_events:currentEvents.size,buckets:learned,
current_samples:currentOutcomes.length,current_markets:currentMarkets.size,current_events:currentEvents.size,buckets:learned,
promoted_buckets:learnedRows.filter(r=>r.weight>=8& & r.lower_bound>0.003).length,
promoted_buckets:learnedRows.filter(r=>r.weight>=8& & r.current_weight>=5 & & r. lower_bound>0.003).length,
demoted_buckets:learnedRows.filter(r=>r.weight>=8& & r.upper_bound< -0.003 ) . length ,
demoted_buckets:learnedRows.filter(r=>r.weight>=8& & r.current_weight>=5 & & r. upper_bound< -0.003 ) . length ,
expired_ungraded:Number(ledger& & ledger.expired_ungraded||0),
expired_ungraded:Number(ledger& & ledger.expired_ungraded||0),
pending:((ledger&&ledger.pending)||[]).length};
pending:((ledger&&ledger.pending)||[]).length};
}
}
function calibratedOpportunity(s,calibration){
function calibratedOpportunity(s,calibration){
const row s=learningFeatures(s).map(k=> calibration&&calibration.buckets&&calibration.buckets[k]).filter(Boolean) ;
const feature s=learningFeatures(s),buckets= calibration&&calibration.buckets||{} ;
const rows=features.map(k=>buckets[k]).filter(Boolean);
const independentWeight=rows.length?Math.max(...rows.map(r=>Number(r.weight||0))):0;
const independentWeight=rows.length?Math.max(...rows.map(r=>Number(r.weight||0))):0;
const score=rows.length?rows.reduce((sum,r)=>sum+r.score,0)/rows.length:0,confidence=independentWeight/(independentWeight+20);
const score=rows.length?rows.reduce((sum,r)=>sum+r.score,0)/rows.length:0,confidence=independentWeight/(independentWeight+20);
const positiveRows=rows.filter(r=>Number(r.weight||0)>=8 &&Number(r.lower_bound||0)>0.003 );
const horizonRows=features.map(feature=>({feature,rows:SIGNAL_EVAL_HORIZONS.map(horizon=>buckets[`${feature}|horizon:${horizon}`])}) );
const negativeRows=rows.filter(r =>Number(r.weight||0)>=8&&Number(r.upper_bound||0)<-0.003) ;
const rowIsCurrent=(row) =>Number(row &&row .weight||0)>=8&&Number(row&&row.current_weight||0)>=5 ;
const positiveRows=horizonRows.filter(group=>group.rows.every(row=>rowIsCurrent(row)&&Number(row.lower_bound||0)>0.003));
const negativeRows=horizonRows.filter(group=>group.rows.some(row=>rowIsCurrent(row)&&Number(row.upper_bound||0)<-0.003));
const promoted=positiveRows.length>=2&&negativeRows.length===0;
const promoted=positiveRows.length>=2&&negativeRows.length===0;
const demoted=negativeRows.length>=2&&positiveRows.length===0;
const demoted=negativeRows.length>=2&&positiveRows.length===0;
const trustedScore=promoted?positiveRows.reduce((sum,r )=>sum+Number(r.lower_bound||0),0)/positiveRows.length
const trustedScore=promoted?positiveRows.reduce((sum,group )=>sum+Math.min(...group.rows.map(row=> Number(row .lower_bound||0))) ,0)/positiveRows.length
:(demoted?negativeRows.reduce((sum,r )=>sum+Number(r.upper_bound||0),0)/negativeRows.length:score*0.10);
:(demoted?negativeRows.reduce((sum,group )=>sum+Math.min(...group.rows.filter(rowIsCurrent).map(row=> Number(row .upper_bound||0))) ,0)/negativeRows.length:score*0.10);
const state=promoted?"promoted":(demoted?"demoted":"observing");
const state=promoted?"promoted":(demoted?"demoted":"observing");
return {score:+score.toFixed(4),confidence:+confidence.toFixed(3),state,promoted,demoted,
return {score:+score.toFixed(4),confidence:+confidence.toFixed(3),state,promoted,demoted,
supporting_features:promoted?positiveRows.length:negativeRows.length,
supporting_features:promoted?positiveRows.length:negativeRows.length,
@@ -1943,10 +1973,11 @@ function historicalOpportunityPrior(s){
requiredPromotionFeatures:[...new Set(rows.flatMap(row=>row.requiredPromotionFeatures||[]))],features:rows.map(row=>row.feature)};
requiredPromotionFeatures:[...new Set(rows.flatMap(row=>row.requiredPromotionFeatures||[]))],features:rows.map(row=>row.feature)};
}
}
function historicalPromotionMet(historical,calibrationModel){
function historicalPromotionMet(historical,calibrationModel){
return !historical.requiresPromotion||historical.requiredPromotionFeatures.every(key=>{
const buckets=calibrationModel&&calibrationModel.buckets||{};
const row=calibrationModel&&calibrationModel.buckets&&calibrationModel.buckets[key];
return !historical.requiresPromotion||historical.requiredPromotionFeatures.every(key=>SIGNAL_EVAL_HORIZONS.every(horizon=>{
return Number(row&&row.weight||0)>=8&&Number(row&&row.lower_bound||0)>0.003;
const row=buckets[`${key}|horizon:${horizon}`];
});
return Number(row&&row.weight||0)>=8&&Number(row&&row.current_weight||0)>=5&&Number(row&&row.lower_bound||0)>0.003;
}));
}
}
function applyAdaptiveMarketPromotion(s,calibrationModel){
function applyAdaptiveMarketPromotion(s,calibrationModel){
if(!s||s.trade_ready||!s.entry_candidate)return s;
if(!s||s.trade_ready||!s.entry_candidate)return s;
@@ -2664,8 +2695,8 @@ async function runDailyCycle(){
SNAP_TS=nowIso();
SNAP_TS=nowIso();
let markets=[],analysisMarkets=[],sugs=[],bundleSugs=[],cache=loadMarketCache(),runMode="live",cacheAgeMs=0;
let markets=[],analysisMarkets=[],sugs=[],bundleSugs=[],cache=loadMarketCache(),runMode="live",cacheAgeMs=0;
try{
try{
setStatus("loading the 500 most active markets…",true);
setStatus("loading the 500 most active eligible markets…",true);
markets=await fetchMarkets(Math.ceil(ACTIVE_MARKET_FETCH_LIMIT/100) ,100,count=>setStatus(`loaded ${Math.min(count,ACTIVE_MARKET_FETCH_LIMIT).toLocaleString()} of 500 active markets…`,true));
markets=await fetchMarkets(20 ,100,count=>setStatus(`loaded ${Math.min(count,ACTIVE_MARKET_FETCH_LIMIT).toLocaleString()} of 500 eligible active markets…`,true),ACTIVE_MARKET_FETCH_LIMIT );
analysisMarkets=selectMarketsForAnalysis(markets);
analysisMarkets=selectMarketsForAnalysis(markets);
if(!analysisMarkets.length)throw new Error("No active markets returned");
if(!analysisMarkets.length)throw new Error("No active markets returned");
setStatus(`analyzing ${analysisMarkets.length.toLocaleString()} most-active markets…`,true);
setStatus(`analyzing ${analysisMarkets.length.toLocaleString()} most-active markets…`,true);
@@ -2929,7 +2960,7 @@ function decisionSummary(p){
const blockerRows=Object.entries(d.rejectionCounts||{}).filter(([,count])=>count>0).sort((a,b)=>b[1]-a[1]);
const blockerRows=Object.entries(d.rejectionCounts||{}).filter(([,count])=>count>0).sort((a,b)=>b[1]-a[1]);
const blockers=blockerRows.length?` Blocks: ${blockerRows.slice(0,4).map(([key,count])=>`${blockerLabels[key]||key} ${count}`).join(", ")}.`:"";
const blockers=blockerRows.length?` Blocks: ${blockerRows.slice(0,4).map(([key,count])=>`${blockerLabels[key]||key} ${count}`).join(", ")}.`:"";
const learning=d.learning?` Learning: ${d.learning.samples} completed trades retained with older strategies down-weighted, ${(d.learning.global_score*100).toFixed(2)}% shrunk expectancy; ${d.learning.current_samples||0} completed under adaptive strategy ${SUGGESTION_ENGINE_VERSION}${d.learning.best?`; strongest ${d.learning.best.feature.replace(":"," ")}`:""}${d.learning.worst?`; weakest ${d.learning.worst.feature.replace(":"," ")}`:""}.`:"";
const learning=d.learning?` Learning: ${d.learning.samples} completed trades retained with older strategies down-weighted, ${(d.learning.global_score*100).toFixed(2)}% shrunk expectancy; ${d.learning.current_samples||0} completed under adaptive strategy ${SUGGESTION_ENGINE_VERSION}${d.learning.best?`; strongest ${d.learning.best.feature.replace(":"," ")}`:""}${d.learning.worst?`; weakest ${d.learning.worst.feature.replace(":"," ")}`:""}.`:"";
const calibration=d.marketLearning?` Walk-forward calibration: ${d.marketLearning.samples||0} net-of-cost observations across ${d.marketLearning.events||d.marketLearning.markets||0} event clusters / ${d.marketLearning.markets||0} markets graded afte r ${SIGNAL_EVAL_HOURS} hours (${d.marketLearning.current_samples||0} observations / ${d.marketLearning.current_events||0} events under adaptive strategy ${SUGGESTION_ENGINE_VERSION}), ${d.marketLearning.pending||0} awaiting a future price ${d.marketLearning.expired_ungraded?`, ${d.marketLearning.expired_ungraded} expired ungraded `:""}; ${d.marketLearning.promoted_buckets||0} feature cohorts promoted and ${d.marketLearning.demoted_buckets||0} demoted. New observations prioritize under-sampled signal/side/category cohorts and independent events before repeats. Correlated outcome markets in one event are clustered into one effective outcome, and matured markets are repriced after leaving the active scan. Uncertainty gates sizing . Historical prior: every directional trend and reversal remains observation-only until its exact recent cohorts independently promote; settlement-jump barriers stay excluded.`:"";
const calibration=d.marketLearning?` Walk-forward calibration: ${d.marketLearning.samples||0} net-of-cost checkpoint observations across ${d.marketLearning.events||d.marketLearning.markets||0} event clusters / ${d.marketLearning.markets||0} markets, graded separately nea r ${SIGNAL_EVAL_HORIZONS.join("h and ")}h (${d.marketLearning.current_samples||0} observations / ${d.marketLearning.current_events||0} events under adaptive strategy ${SUGGESTION_ENGINE_VERSION}), ${d.marketLearning.pending||0} awaiting a future checkpoint ${d.marketLearning.expired_ungraded?`, ${d.marketLearning.expired_ungraded} expired checkpoints `:""}; ${d.marketLearning.promoted_buckets||0} horizon-specific feature cohorts promoted and ${d.marketLearning.demoted_buckets||0} demoted. Promotion requires positive current-strategy evidence at both horizons across independent events. Missed windows expire rather than borrowing a later price. New observations prioritize under-sampled signal/side/category cohorts and independent events before repeats. Correlated outcome markets in one event count as one effective outcome. Historical prior: every directional trend and reversal remains observation-only until its exact recent cohorts independently promote; settlement-jump barriers stay excluded.`:"";
return `${d.mode} mode: ${d.reason}${emotion} Limits now: ${d.maxNew} new trade${d.maxNew===1?"":"s"}, max ${(d.maxFrac*100).toFixed(1)}% per position${d.minConv?`, conviction ${d.minConv}+`:""}.${learning}${calibration}${exposure}${allocation}${candidates}${blockers}`;
return `${d.mode} mode: ${d.reason}${emotion} Limits now: ${d.maxNew} new trade${d.maxNew===1?"":"s"}, max ${(d.maxFrac*100).toFixed(1)}% per position${d.minConv?`, conviction ${d.minConv}+`:""}.${learning}${calibration}${exposure}${allocation}${candidates}${blockers}`;
}
}
function renderAgentBrief(cfg,p,st){
function renderAgentBrief(cfg,p,st){
@@ -4523,7 +4554,7 @@ window.PMA_ENGINE_DIAGNOSTICS=Object.freeze({
coreGapTradeLossPct:MAX_CORE_GAP_TRADE_LOSS_PCT*100,aggressiveGapTradeLossPct:MAX_AGGRESSIVE_GAP_TRADE_LOSS_PCT*100,
coreGapTradeLossPct:MAX_CORE_GAP_TRADE_LOSS_PCT*100,aggressiveGapTradeLossPct:MAX_AGGRESSIVE_GAP_TRADE_LOSS_PCT*100,
offlineEntryMaxAgeMinutes:OFFLINE_ENTRY_MAX_AGE_MS/60000,offlineCacheMaxAgeHours:OFFLINE_CACHE_MAX_AGE_MS/3600000,explorationPct:15,
offlineEntryMaxAgeMinutes:OFFLINE_ENTRY_MAX_AGE_MS/60000,offlineCacheMaxAgeHours:OFFLINE_CACHE_MAX_AGE_MS/3600000,explorationPct:15,
networkTimeoutSeconds:NETWORK_REQUEST_TIMEOUT_MS/1000,priceTimeoutSeconds:PRICE_REQUEST_TIMEOUT_MS/1000,
networkTimeoutSeconds:NETWORK_REQUEST_TIMEOUT_MS/1000,priceTimeoutSeconds:PRICE_REQUEST_TIMEOUT_MS/1000,
staleCacheIsMarkOnly:true,strategyEvidenceSurvivesBuilds:true,signalEvaluationHours:SIGNAL_EVAL_HOURS,signalRetryHours:SIGNAL_LEDGER_RETRY_HOURS,
staleCacheIsMarkOnly:true,strategyEvidenceSurvivesBuilds:true,signalEvaluationHours:SIGNAL_EVAL_HOURS,signalEvaluationHorizons:SIGNAL_EVAL_HORIZONS,signalEvaluationToleranceHours:SIGNAL_EVAL_TOLERANCE_HOURS, signalRetryHours:SIGNAL_LEDGER_RETRY_HOURS,
signalDueFetchLimit:SIGNAL_LEDGER_DUE_FETCH_LIMIT,survivorshipSafeSignalGrading:true,
signalDueFetchLimit:SIGNAL_LEDGER_DUE_FETCH_LIMIT,survivorshipSafeSignalGrading:true,
signalRoundTripCostCents:SIGNAL_ROUND_TRIP_COST*100,independentConfidence:true,eventClusteredCalibration:true,
signalRoundTripCostCents:SIGNAL_ROUND_TRIP_COST*100,independentConfidence:true,eventClusteredCalibration:true,
onePendingObservationPerMarketSide:true,oldestPendingEvidenceFirst:true,coverageAwareObservationSampling:true,uncertaintyGatedCalibration:true,
onePendingObservationPerMarketSide:true,oldestPendingEvidenceFirst:true,coverageAwareObservationSampling:true,uncertaintyGatedCalibration:true,
@@ -4564,8 +4595,8 @@ function runEngineSelfTest(){
realized_pnl:-20,opened_at:hoursAgo(72+i),closed_at:closedAt});
realized_pnl:-20,opened_at:hoursAgo(72+i),closed_at:closedAt});
const learningProfile=buildAdaptiveProfile(learner);
const learningProfile=buildAdaptiveProfile(learner);
const calibrationLedger=defaultSignalLedger();
const calibrationLedger=defaultSignalLedger();
for(let i=0;i< 16 ; i + + ) calibrationLedger . outcomes . push ( { market_id: ` trend-market- $ { i } ` , event_key: ` trend-event- $ { i } ` , signal_type: " trend " , quality: " confirmed " , category: " Politics " , side: " YES " , entry_price:0 . 42 , return:0 . 12 , evaluated_at:closedAt } ) ;
for(let i=0;i< 16 ; i + + ) SIGNAL_EVAL_HORIZONS . forEach ( horizon = > calibrationLedger.outcomes.push({market_id:`trend-market-${i}`,event_key:`trend-event-${i}`,signal_type:"trend",quality:"confirmed",category:"Politics",side:"YES",entry_price:0.42,target_horizon_hours:horizon,strategy_version:SUGGESTION_ENGINE_VERSION, return:0.12, evaluated_at:closedAt}));
for(let i=0;i< 16 ; i + + ) calibrationLedger . outcomes . push ( { market_id: ` reversal-market- $ { i } ` , event_key: ` reversal-event- $ { i } ` , signal_type: " reversal " , quality: " reversal " , category: " Sports " , side: " NO " , entry_price:0 . 42 , return:-0 . 12 , evaluated_at:closedAt } ) ;
for(let i=0;i< 16 ; i + + ) SIGNAL_EVAL_HORIZONS . forEach ( horizon = > calibrationLedger.outcomes.push({market_id:`reversal-market-${i}`,event_key:`reversal-event-${i}`,signal_type:"reversal",quality:"reversal",category:"Sports",side:"NO",entry_price:0.42,target_horizon_hours:horizon,strategy_version:SUGGESTION_ENGINE_VERSION, return:-0.12, evaluated_at:closedAt}));
const calibrationProfile=buildSignalCalibration(calibrationLedger);
const calibrationProfile=buildSignalCalibration(calibrationLedger);
const learnedTrend=learnedOpportunity(AGENTS[0],learner,{market_id:"learn-trend",signal_type:"trend",quality:"confirmed",category:"Politics",side:"YES",entry_price:0.42},learningProfile,calibrationProfile);
const learnedTrend=learnedOpportunity(AGENTS[0],learner,{market_id:"learn-trend",signal_type:"trend",quality:"confirmed",category:"Politics",side:"YES",entry_price:0.42},learningProfile,calibrationProfile);
const learnedReversal=learnedOpportunity(AGENTS[0],learner,{market_id:"learn-reversal",signal_type:"reversal",quality:"reversal",category:"Sports",side:"NO",entry_price:0.42},learningProfile,calibrationProfile);
const learnedReversal=learnedOpportunity(AGENTS[0],learner,{market_id:"learn-reversal",signal_type:"reversal",quality:"reversal",category:"Sports",side:"NO",entry_price:0.42},learningProfile,calibrationProfile);
@@ -4583,9 +4614,15 @@ function runEngineSelfTest(){
const ledgerState={signal_ledger:{pending:[{key:"ledger-test",market_id:"ledger-test",observed_at:hoursAgo(25),side:"YES",entry_price:0.40,
const ledgerState={signal_ledger:{pending:[{key:"ledger-test",market_id:"ledger-test",observed_at:hoursAgo(25),side:"YES",entry_price:0.40,
signal_type:"trend",quality:"confirmed",category:"Politics"}],outcomes:[]}};
signal_type:"trend",quality:"confirmed",category:"Politics"}],outcomes:[]}};
updateSignalLedger(ledgerState,[market({id:"ledger-test",yes_price:0.50,no_price:0.50})],[]);
updateSignalLedger(ledgerState,[market({id:"ledger-test",yes_price:0.50,no_price:0.50})],[]);
const secondHorizonState={signal_ledger:{pending:[{key:"ledger-second",market_id:"ledger-second",observed_at:hoursAgo(73),graded_horizons:[24],side:"YES",entry_price:0.40,
signal_type:"trend",quality:"confirmed",category:"Politics"}],outcomes:[]}};
updateSignalLedger(secondHorizonState,[market({id:"ledger-second",yes_price:0.52,no_price:0.48})],[]);
const earlyLedgerState={signal_ledger:{pending:[{key:"ledger-early",market_id:"ledger-early",observed_at:hoursAgo(13),side:"YES",entry_price:0.40,
const earlyLedgerState={signal_ledger:{pending:[{key:"ledger-early",market_id:"ledger-early",observed_at:hoursAgo(13),side:"YES",entry_price:0.40,
signal_type:"trend",quality:"confirmed",category:"Politics"}],outcomes:[]}};
signal_type:"trend",quality:"confirmed",category:"Politics"}],outcomes:[]}};
updateSignalLedger(earlyLedgerState,[market({id:"ledger-early",yes_price:0.50,no_price:0.50})],[]);
updateSignalLedger(earlyLedgerState,[market({id:"ledger-early",yes_price:0.50,no_price:0.50})],[]);
const missedFirstWindowState={signal_ledger:{pending:[{key:"ledger-missed-24",market_id:"ledger-missed-24",observed_at:hoursAgo(31),side:"YES",entry_price:0.40,
signal_type:"trend",quality:"confirmed",category:"Politics"}],outcomes:[]}};
updateSignalLedger(missedFirstWindowState,[market({id:"ledger-missed-24",yes_price:0.90,no_price:0.10})],[]);
const observationLedgerState={signal_ledger:defaultSignalLedger()};
const observationLedgerState={signal_ledger:defaultSignalLedger()};
updateSignalLedger(observationLedgerState,[],[{market_id:"observation-only",side:"YES",entry_price:0.42,signal_type:"trend",quality:"watch",
updateSignalLedger(observationLedgerState,[],[{market_id:"observation-only",side:"YES",entry_price:0.42,signal_type:"trend",quality:"watch",
signal_confidence:0.62,trade_ready:false,jump_risk:false,category:"Politics",days_to_resolution:45}]);
signal_confidence:0.62,trade_ready:false,jump_risk:false,category:"Politics",days_to_resolution:45}]);
@@ -4609,21 +4646,25 @@ function runEngineSelfTest(){
{key:"outside-b",market_id:"outside-active-scan",observed_at:hoursAgo(25)},
{key:"outside-b",market_id:"outside-active-scan",observed_at:hoursAgo(25)},
{key:"young",market_id:"too-young",observed_at:hoursAgo(2)}],outcomes:[]};
{key:"young",market_id:"too-young",observed_at:hoursAgo(2)}],outcomes:[]};
const dueFetchIds=pendingSignalMarketIds(dueFetchLedger,new Set(["known-active"]));
const dueFetchIds=pendingSignalMarketIds(dueFetchLedger,new Set(["known-active"]));
const retryLedgerState={signal_ledger:{pending:[{key:"retry",market_id:"temporarily-unavailable",observed_at:hoursAgo(100 ),side:"YES",entry_price:0.4}],outcomes:[]}};
const retryLedgerState={signal_ledger:{pending:[{key:"retry",market_id:"temporarily-unavailable",observed_at:hoursAgo(25 ),side:"YES",entry_price:0.4}],outcomes:[]}};
updateSignalLedger(retryLedgerState,[],[]);
updateSignalLedger(retryLedgerState,[],[]);
const expiredLedgerState={signal_ledger:{pending:[{key:"expired",market_id:"never-returned",observed_at:hoursAgo(16 9),side:"YES",entry_price:0.4}],outcomes:[]}};
const expiredLedgerState={signal_ledger:{pending:[{key:"expired",market_id:"never-returned",observed_at:hoursAgo(7 9),side:"YES",entry_price:0.4}],outcomes:[]}};
updateSignalLedger(expiredLedgerState,[],[]);
updateSignalLedger(expiredLedgerState,[],[]);
const calibrationCandidate={signal_type:"trend",quality:"confirmed",category:"Politics",side:"YES",entry_price:0.42};
const calibrationCandidate={signal_type:"trend",quality:"confirmed",category:"Politics",side:"YES",entry_price:0.42};
const calibrationFromReturns=(returns,candidate=calibrationCandidate)=>buildSignalCalibration({pending:[],outcomes:returns.m ap((ret,index)=>Object.assign({},candidate,
const calibrationFromReturns=(returns,candidate=calibrationCandidate,horizons=SIGNAL_EVAL_HORIZONS )=>buildSignalCalibration({pending:[],outcomes:returns.flatM ap((ret,index)=>horizons.map(horizon=> Object.assign({},candidate,
{market_id:`${candidate.market_id||"calibration"}-${index}`,event_key:`${candidate.event_key||candidate.market_id||"calibration-event"}-${index}`,
{market_id:`${candidate.market_id||"calibration"}-${index}`,event_key:`${candidate.event_key||candidate.market_id||"calibration-event"}-${index}`,
strategy_version:SUGGESTION_ENGINE_VERSION,return:ret,evaluated_at:closedAt}))});
target_horizon_hours:horizon, strategy_version:SUGGESTION_ENGINE_VERSION,return:ret,evaluated_at:closedAt}))) });
const repeatedMarketCalibration=buildSignalCalibration({pending:[],outcomes:Array.from({length:24},()=>Object.assign({},calibrationCandidate,
const repeatedMarketCalibration=buildSignalCalibration({pending:[],outcomes:Array.from({length:24},()=>SIGNAL_EVAL_HORIZONS.map(horizon=> Object.assign({},calibrationCandidate,
{market_id:"one-repeated-market",event_key:"one-repeated-event",strategy_version:SUGGESTION_ENGINE_VERSION,return:0.12,evaluated_at:closedAt}))});
{market_id:"one-repeated-market",event_key:"one-repeated-event",target_horizon_hours:horizon, strategy_version:SUGGESTION_ENGINE_VERSION,return:0.12,evaluated_at:closedAt}))).flat() });
const repeatedMarketState=calibratedOpportunity(calibrationCandidate,repeatedMarketCalibration);
const repeatedMarketState=calibratedOpportunity(calibrationCandidate,repeatedMarketCalibration);
const correlatedEventCalibration=buildSignalCalibration({pending:[],outcomes:Array.from({length:24},(_,index)=>Object.assign({},calibrationCandidate,
const correlatedEventCalibration=buildSignalCalibration({pending:[],outcomes:Array.from({length:24},(_,index)=>SIGNAL_EVAL_HORIZONS.map(horizon=> Object.assign({},calibrationCandidate,
{market_id:`correlated-market-${index}`,event_key:"one-correlated-event",strategy_version:SUGGESTION_ENGINE_VERSION,return:0.12,evaluated_at:closedAt}))});
{market_id:`correlated-market-${index}`,event_key:"one-correlated-event",target_horizon_hours:horizon, strategy_version:SUGGESTION_ENGINE_VERSION,return:0.12,evaluated_at:closedAt}))).flat() });
const correlatedEventState=calibratedOpportunity(calibrationCandidate,correlatedEventCalibration);
const correlatedEventState=calibratedOpportunity(calibrationCandidate,correlatedEventCalibration);
const singleCalibration=calibratedOpportunity(calibrationCandidate,calibrationFromReturns([0.10]));
const singleCalibration=calibratedOpportunity(calibrationCandidate,calibrationFromReturns([0.10]));
const oneHorizonPositiveCalibration=calibratedOpportunity(calibrationCandidate,calibrationFromReturns(Array(24).fill(0.12),calibrationCandidate,[24]));
const previousOnlyProfile=buildSignalCalibration({pending:[],outcomes:Array.from({length:24},(_,index)=>SIGNAL_EVAL_HORIZONS.map(horizon=>Object.assign({},calibrationCandidate,
{market_id:`previous-only-${index}`,event_key:`previous-only-event-${index}`,target_horizon_hours:horizon,strategy_version:PREVIOUS_STRATEGY_VERSION,return:0.12,evaluated_at:closedAt}))).flat()});
const previousOnlyCalibration=calibratedOpportunity(calibrationCandidate,previousOnlyProfile);
const stablePositiveProfile=calibrationFromReturns(Array(24).fill(0.12));
const stablePositiveProfile=calibrationFromReturns(Array(24).fill(0.12));
const stablePositiveCalibration=calibratedOpportunity(calibrationCandidate,stablePositiveProfile);
const stablePositiveCalibration=calibratedOpportunity(calibrationCandidate,stablePositiveProfile);
const promotedTrendSuggestion=applyAdaptiveMarketPromotion(Object.assign({},trend,{entry_candidate:true}),stablePositiveProfile);
const promotedTrendSuggestion=applyAdaptiveMarketPromotion(Object.assign({},trend,{entry_candidate:true}),stablePositiveProfile);
@@ -4685,20 +4726,25 @@ function runEngineSelfTest(){
const retiredFixture=accountingBook(0.45),retiredEquityBefore=equity(retiredFixture.book);
const retiredFixture=accountingBook(0.45),retiredEquityBefore=equity(retiredFixture.book);
retiredFixture.pos.strategy_version=PREVIOUS_STRATEGY_VERSION;
retiredFixture.pos.strategy_version=PREVIOUS_STRATEGY_VERSION;
markToMarket(retiredFixture.book,{[retiredFixture.pos.market_id]:market({id:retiredFixture.pos.market_id,yes_price:0.45,no_price:0.55})},AGENTS[0],{policyExits:true,executeTrades:true});
markToMarket(retiredFixture.book,{[retiredFixture.pos.market_id]:market({id:retiredFixture.pos.market_id,yes_price:0.45,no_price:0.55})},AGENTS[0],{policyExits:true,executeTrades:true});
const nonBinaryMarketRejected=normalizeMarket({id:"over-under-test",question:"Over/Under 2.5",outcomes:'["Over","Under"]',outcomePrices:'["0.5","0.5"]',acceptingOrders:true})===null;
const bundleSuggestion=negativeRiskBundleSuggestion({id:"bundle-test",title:"Three-way result",slug:"bundle-test",negRisk:true,enableNegRisk:true,tags:[{slug:"sports",label:"Sports"}],markets:[
const bundleSuggestion=negativeRiskBundleSuggestion({id:"bundle-test",title:"Three-way result",slug:"bundle-test",negRisk:true,enableNegRisk:true,tags:[{slug:"sports",label:"Sports"}],markets:[
{id:"bundle-a",question:"A wins",outcomePrices:'["0.415","0.585"]',clobTokenIds:'["a-yes","a-no"]',bestBid:0.41,bestAsk:0.42,liquidityNum:30000,volumeNum:100000,volume24hr:10000,acceptingOrders:true},
{id:"bundle-a",question:"A wins",outcomes:'["Yes","No"]', outcomePrices:'["0.415","0.585"]',clobTokenIds:'["a-yes","a-no"]',bestBid:0.41,bestAsk:0.42,liquidityNum:30000,volumeNum:100000,volume24hr:10000,acceptingOrders:true},
{id:"bundle-b",question:"B wins",outcomePrices:'["0.315","0.685"]',clobTokenIds:'["b-yes","b-no"]',bestBid:0.31,bestAsk:0.32,liquidityNum:28000,volumeNum:100000,volume24hr:10000,acceptingOrders:true},
{id:"bundle-b",question:"B wins",outcomes:'["Yes","No"]', outcomePrices:'["0.315","0.685"]',clobTokenIds:'["b-yes","b-no"]',bestBid:0.31,bestAsk:0.32,liquidityNum:28000,volumeNum:100000,volume24hr:10000,acceptingOrders:true},
{id:"bundle-draw",question:"Draw",outcomePrices:'["0.305","0.695"]',clobTokenIds:'["d-yes","d-no"]',bestBid:0.30,bestAsk:0.31,liquidityNum:20000,volumeNum:100000,volume24hr:10000,acceptingOrders:true},
{id:"bundle-draw",question:"Draw",outcomes:'["Yes","No"]', outcomePrices:'["0.305","0.695"]',clobTokenIds:'["d-yes","d-no"]',bestBid:0.30,bestAsk:0.31,liquidityNum:20000,volumeNum:100000,volume24hr:10000,acceptingOrders:true},
]});
]});
const yesBundleSuggestion=negativeRiskBundleSuggestion({id:"bundle-yes-test",title:"Three-way YES result",slug:"bundle-yes-test",negRisk:true,enableNegRisk:true,markets:[
const yesBundleSuggestion=negativeRiskBundleSuggestion({id:"bundle-yes-test",title:"Three-way YES result",slug:"bundle-yes-test",negRisk:true,enableNegRisk:true,markets:[
{id:"yes-bundle-a",question:"A wins",outcomePrices:'["0.295","0.705"]',clobTokenIds:'["ya-yes","ya-no"]',bestBid:0.29,bestAsk:0.30,liquidityNum:30000,volumeNum:100000,volume24hr:10000,acceptingOrders:true},
{id:"yes-bundle-a",question:"A wins",outcomes:'["Yes","No"]', outcomePrices:'["0.295","0.705"]',clobTokenIds:'["ya-yes","ya-no"]',bestBid:0.29,bestAsk:0.30,liquidityNum:30000,volumeNum:100000,volume24hr:10000,acceptingOrders:true},
{id:"yes-bundle-b",question:"B wins",outcomePrices:'["0.305","0.695"]',clobTokenIds:'["yb-yes","yb-no"]',bestBid:0.30,bestAsk:0.31,liquidityNum:28000,volumeNum:100000,volume24hr:10000,acceptingOrders:true},
{id:"yes-bundle-b",question:"B wins",outcomes:'["Yes","No"]', outcomePrices:'["0.305","0.695"]',clobTokenIds:'["yb-yes","yb-no"]',bestBid:0.30,bestAsk:0.31,liquidityNum:28000,volumeNum:100000,volume24hr:10000,acceptingOrders:true},
{id:"yes-bundle-draw",question:"Draw",outcomePrices:'["0.335","0.665"]',clobTokenIds:'["yd-yes","yd-no"]',bestBid:0.33,bestAsk:0.34,liquidityNum:20000,volumeNum:100000,volume24hr:10000,acceptingOrders:true},
{id:"yes-bundle-draw",question:"Draw",outcomes:'["Yes","No"]', outcomePrices:'["0.335","0.665"]',clobTokenIds:'["yd-yes","yd-no"]',bestBid:0.33,bestAsk:0.34,liquidityNum:20000,volumeNum:100000,volume24hr:10000,acceptingOrders:true},
]});
]});
const tinyReturnBundle=negativeRiskBundleSuggestion({id:"bundle-tiny",title:"Ten-way result",slug:"bundle-tiny",negRisk:true,enableNegRisk:true,markets:Array.from({length:10},(_,i)=>({
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}`,outcomePrices:'["0.1055","0.8945"]',clobTokenIds:`["tiny-${i}-yes","tiny-${i}-no"]`,
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,
bestBid:0.1055,bestAsk:0.1065,liquidityNum:30000,volumeNum:100000,volume24hr:10000,acceptingOrders:true,
}))});
}))});
const nonBinaryBundleRejected=negativeRiskBundleSuggestion({id:"bundle-label-test",title:"Over/Under",slug:"bundle-label-test",negRisk:true,enableNegRisk:true,markets:[
{id:"over-a",question:"Over/Under 1.5",outcomes:'["Over","Under"]',outcomePrices:'["0.45","0.55"]',clobTokenIds:'["over-a","under-a"]',bestBid:0.44,bestAsk:0.45,liquidityNum:30000,acceptingOrders:true},
{id:"over-b",question:"Over/Under 2.5",outcomes:'["Over","Under"]',outcomePrices:'["0.45","0.55"]',clobTokenIds:'["over-b","under-b"]',bestBid:0.44,bestAsk:0.45,liquidityNum:30000,acceptingOrders:true},
]})===null;
const bundleBook=defaultPortfolio();
const bundleBook=defaultPortfolio();
const offlineBundleSuggestion=prepareCycleSuggestions([bundleSuggestion],"offline-cache",true)[0];
const offlineBundleSuggestion=prepareCycleSuggestions([bundleSuggestion],"offline-cache",true)[0];
openPositions(bundleBook,AGENTS.find(a=>a.id==="value"),[bundleSuggestion],"All",{
openPositions(bundleBook,AGENTS.find(a=>a.id==="value"),[bundleSuggestion],"All",{
@@ -4815,20 +4861,26 @@ function runEngineSelfTest(){
& & queueLedgerState.signal_ledger.pending.some(x=>x.market_id==="new-market-0")
& & queueLedgerState.signal_ledger.pending.some(x=>x.market_id==="new-market-0")
& & !queueLedgerState.signal_ledger.pending.some(x=>x.market_id==="new-market-1"),
& & !queueLedgerState.signal_ledger.pending.some(x=>x.market_id==="new-market-1"),
underObservedCohortsAndEventsSampleFirst:coveragePriority.map(x=>x.market_id).join(",")==="new-sports,new-politics,popular-repeat",
underObservedCohortsAndEventsSampleFirst:coveragePriority.map(x=>x.market_id).join(",")==="new-sports,new-politics,popular-repeat",
ledgerMatur esWithoutLookahead:ledgerState.signal_ledger.pending.length===0 & & ledgerState.signal_ledger.outcomes.length===1 & & ledgerState.signal_ledger.outcomes[0].return===0.2375,
firstHorizonGrad esWithoutLookahead:ledgerState.signal_ledger.pending.length===1 & & ledgerState.signal_ledger.pending[0].graded_horizons.includes(24)
& & ledgerState.signal_ledger.outcomes.length===1& & ledgerState.signal_ledger.outcomes[0].target_horizon_hours===24& & ledgerState.signal_ledger.outcomes[0].return===0.2375,
secondHorizonGradesAndCompletes:secondHorizonState.signal_ledger.pending.length===0& & secondHorizonState.signal_ledger.outcomes.length===1
& & secondHorizonState.signal_ledger.outcomes[0].target_horizon_hours===72,
holdsSignalsUntilPolicyHorizon:earlyLedgerState.signal_ledger.pending.length===1& & earlyLedgerState.signal_ledger.outcomes.length===0,
holdsSignalsUntilPolicyHorizon:earlyLedgerState.signal_ledger.pending.length===1& & earlyLedgerState.signal_ledger.outcomes.length===0,
missed24hWindowIsNotBackfilled:missedFirstWindowState.signal_ledger.pending.length===1& & missedFirstWindowState.signal_ledger.outcomes.length===0,
fetchesMaturedMarketsOutsideActiveScan:dueFetchIds.length===1& & dueFetchIds[0]==="outside-active-scan",
fetchesMaturedMarketsOutsideActiveScan:dueFetchIds.length===1& & dueFetchIds[0]==="outside-active-scan",
keepsUnavailableGradesQueued:retryLedgerState.signal_ledger.pending.length===1& & retryLedgerState.signal_ledger.outcomes.length===0,
keepsUnavailableGradesQueued:retryLedgerState.signal_ledger.pending.length===1& & retryLedgerState.signal_ledger.outcomes.length===0,
expiresOnlyAfterRetryWindow:expiredLedgerState.signal_ledger.pending.length===0& & expiredLedgerState.signal_ledger.expired_ungraded===1 ,
expiresOnlyAfterRetryWindow:expiredLedgerState.signal_ledger.pending.length===0& & expiredLedgerState.signal_ledger.expired_ungraded===2 ,
ledgerIsNetOfCosts:ledgerState.signal_ledger.outcomes[0].gross_return===0.25& & ledgerState.signal_ledger.outcomes[0].estimated_cost_return===0.0125,
ledgerIsNetOfCosts:ledgerState.signal_ledger.outcomes[0].gross_return===0.25& & ledgerState.signal_ledger.outcomes[0].estimated_cost_return===0.0125,
independentCalibrationConfidence:singleCalibration.confidence< 0.06 ,
independentCalibrationConfidence:singleCalibration.confidence< 0.06 ,
repeatedSnapshotsCountAsOneMarket:repeatedMarketCalibration.markets===1& & repeatedMarketCalibration.buckets["signal:trend"].samples===1
repeatedSnapshotsCountAsOneMarket:repeatedMarketCalibration.markets===1& & repeatedMarketCalibration.buckets["signal:trend"].samples===1
& & repeatedMarketCalibration.buckets["signal:trend"].observations===2 4& & repeatedMarketState.state==="observing",
& & repeatedMarketCalibration.buckets["signal:trend"].observations===48 & & repeatedMarketState.state==="observing",
correlatedMarketsCountAsOneEvent:correlatedEventCalibration.markets===24& & correlatedEventCalibration.events===1
correlatedMarketsCountAsOneEvent:correlatedEventCalibration.markets===24& & correlatedEventCalibration.events===1
& & correlatedEventCalibration.buckets["signal:trend"].samples===1& & correlatedEventState.state==="observing",
& & correlatedEventCalibration.buckets["signal:trend"].samples===1& & correlatedEventState.state==="observing",
stablePositiveEventCount:stablePositiveProfile.events,
stablePositiveEventCount:stablePositiveProfile.events,
stablePositiveMarketCount:stablePositiveProfile.markets,
stablePositiveMarketCount:stablePositiveProfile.markets,
distinctEventsCanPromote:stablePositiveProfile.events===24& & stablePositiveCalibration.state==="promoted"& & stablePositiveCalibration.supporting_features>=2,
distinctEventsCanPromote:stablePositiveProfile.events===24& & stablePositiveCalibration.state==="promoted"& & stablePositiveCalibration.supporting_features>=2,
oneHorizonCannotPromote:oneHorizonPositiveCalibration.state==="observing"& & !oneHorizonPositiveCalibration.promoted,
previousStrategyCannotPromote:previousOnlyCalibration.state==="observing"& & !previousOnlyCalibration.promoted,
legacyBuildLineageRemainsHistorical:normalizedStrategyVersion(41)===40,
legacyBuildLineageRemainsHistorical:normalizedStrategyVersion(41)===40,
previousStrategyIsDownWeighted:legacyBuildCalibration.current_samples===0& & legacyBuildCalibration.buckets["signal:trend"].weight>0.54& & legacyBuildCalibration.buckets["signal:trend"].weight< =0.55,
previousStrategyIsDownWeighted:legacyBuildCalibration.current_samples===0& & legacyBuildCalibration.buckets["signal:trend"].weight>0.54& & legacyBuildCalibration.buckets["signal:trend"].weight< =0.55,
currentStrategyKeepsFullWeight:currentStrategyCalibration.current_samples===1& & currentStrategyCalibration.buckets["signal:trend"].weight>0.99,
currentStrategyKeepsFullWeight:currentStrategyCalibration.current_samples===1& & currentStrategyCalibration.buckets["signal:trend"].weight>0.99,
@@ -4857,6 +4909,8 @@ function runEngineSelfTest(){
adaptiveReturnSetsLeader:adaptiveRankFixture[0].c.id==="adaptive-leader",
adaptiveReturnSetsLeader:adaptiveRankFixture[0].c.id==="adaptive-leader",
},
},
bundleArbitrage:{
bundleArbitrage:{
rejectsNonBinaryMarketLabels:nonBinaryMarketRejected,
rejectsNonBinaryBundleLabels:nonBinaryBundleRejected,
identifiesPositiveCompleteNoBundle:bundleSuggestion& & bundleSuggestion.trade_ready& & bundleSuggestion.bundle_side==="NO"& & bundleSuggestion.bundle_legs.every(leg=>leg.side==="NO")& & bundleSuggestion.bundle_net_profit_per_unit===0.005,
identifiesPositiveCompleteNoBundle:bundleSuggestion& & bundleSuggestion.trade_ready& & bundleSuggestion.bundle_side==="NO"& & bundleSuggestion.bundle_legs.every(leg=>leg.side==="NO")& & bundleSuggestion.bundle_net_profit_per_unit===0.005,
identifiesPositiveCompleteYesBundle:yesBundleSuggestion& & yesBundleSuggestion.trade_ready& & yesBundleSuggestion.bundle_side==="YES"& & yesBundleSuggestion.bundle_legs.every(leg=>leg.side==="YES")& & yesBundleSuggestion.bundle_net_profit_per_unit===0.035,
identifiesPositiveCompleteYesBundle:yesBundleSuggestion& & yesBundleSuggestion.trade_ready& & yesBundleSuggestion.bundle_side==="YES"& & yesBundleSuggestion.bundle_legs.every(leg=>leg.side==="YES")& & yesBundleSuggestion.bundle_net_profit_per_unit===0.035,
rejectsEconomicallyTinyLargeBundle:tinyReturnBundle===null,
rejectsEconomicallyTinyLargeBundle:tinyReturnBundle===null,