Compare commits

...

2 Commits

Author SHA1 Message Date
Theodore Song 3c39cfe9f3 Force visible top 5000 build 2026-07-26 21:13:02 -04:00
Theodore Song 744387199e Analyze top 5000 active markets 2026-07-26 20:10:39 -04:00
2 changed files with 33 additions and 10 deletions
+1 -1
View File
@@ -135,7 +135,7 @@ export default async function handler(req, res) {
access: "private",
allowOverwrite: true,
contentType: "application/json",
cacheControlMaxAge: 60,
cacheControlMaxAge: 0,
});
return res.status(200).json({ ok: true, state });
}
+32 -9
View File
@@ -53,6 +53,7 @@ h1,h2,h3,.brand-name{font-family:'Space Grotesk','Inter',sans-serif}
background:linear-gradient(135deg,var(--accent),var(--accent2));box-shadow:0 6px 20px -6px var(--accent)}
.brand-name{font-size:18px;font-weight:700;letter-spacing:-.2px;line-height:1}
.brand-sub{font-size:11px;color:var(--muted);margin-top:2px}
.build-badge{display:inline-flex;align-items:center;margin-top:5px;padding:3px 8px;border-radius:999px;border:1px solid rgba(124,140,255,.35);background:rgba(124,140,255,.12);color:#cbd5ff;font-size:10px;font-weight:800;letter-spacing:.02em;text-transform:uppercase}
.tabs{display:flex;gap:4px;background:rgba(255,255,255,.04);padding:4px;border-radius:12px;border:1px solid var(--border);max-width:100%;overflow-x:auto}
.tab{appearance:none;border:0;background:transparent;color:var(--muted);font-family:inherit;
font-size:13.5px;font-weight:600;padding:8px 14px;border-radius:9px;cursor:pointer;transition:.18s;white-space:nowrap}
@@ -337,7 +338,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 · strategies, copycats &amp; whales</div></div>
<div><div class="brand-name">Polymarket Arena</div><div class="brand-sub">10 agents · strategies, copycats &amp; whales</div><div class="build-badge">Top 5,000 analysis · v16</div></div>
</div>
<div class="tabs" id="tabs">
<button class="tab" data-tab="overview">Overview</button>
@@ -739,7 +740,7 @@ footer{margin-top:34px;padding-top:22px;border-top:1px solid var(--border);color
</section>
<footer>
Build hold-fix · Paper trading only · Live prices from Polymarket's public Gamma API · Not financial advice ·
Build top-5000-analysis-v16 · 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>
</footer>
</div>
@@ -766,7 +767,7 @@ const EXIT_STALE_DAYS = 10;
const EXIT_RESOLUTION_DAYS = 2;
const AGENTS_KEY = "pma_agents_v2";
const SUG_KEY = "pma_suggestions_v5";
const SUGGESTION_ENGINE_VERSION = 14;
const SUGGESTION_ENGINE_VERSION = 16;
const FOCUS_KEY = "pma_focus_v1";
const VIEW_KEY = "pma_view_v1";
const PF_SORT_KEY = "pma_portfolio_sort_v1";
@@ -995,6 +996,7 @@ const MIN_ENTRY_DAYS=3.0;
const EDGE_SCALE=0.13;
const MAX_STRATEGY_POSITIONS=16;
const MAX_ACTIVE_MARKET_PAGES=1000;
const MARKET_ANALYSIS_LIMIT=5000;
const SUGGESTION_TOTAL=900;
const SUGGESTION_PER_CATEGORY=180;
const VISIBLE_SUGGESTIONS=900;
@@ -1057,6 +1059,23 @@ function fairValue(m){const p=m.yes_price,mom=momentumSignal(m),liq=liquiditySig
const directional=mom>0.62?(mom-0.62)*0.08:(mom<0.26?(mom-0.26)*0.035:0);
const liquidBump=(liq-0.55)*0.012;
return clamp(p+directional+liquidBump,0.03,0.97);}
function quickMarketGap(m){
if(!m||!Number.isFinite(m.yes_price))return 0;
return Math.abs(fairValue(m)-m.yes_price);
}
function marketAnalysisScore(m){
const activity=Math.log10((m.volume_24hr||0)*8+(m.volume||0)+1);
const liquidity=Math.log10((m.liquidity||0)+1);
const gap=quickMarketGap(m);
const timing=timingSignal(m.days_to_resolution);
return activity*18+liquidity*9+gap*260+timing*8;
}
function selectMarketsForAnalysis(markets,limit=MARKET_ANALYSIS_LIMIT){
return [...markets]
.filter(m=>m&&m.question&&m.volume>=MIN_SCOUT_VOLUME&&m.liquidity>=MIN_SCOUT_LIQUIDITY)
.sort((a,b)=>marketAnalysisScore(b)-marketAnalysisScore(a))
.slice(0,limit);
}
function timingSignal(d){if(d==null)return 0.4;if(d<1)return 0.1;if(d<=3)return 0.5;if(d<=90)return 1.0-(d-3)/87.0*0.4;return 0.35;}
function analyzeMarket(m,realWorldSignals={}){
if(m.volume<MIN_SCOUT_VOLUME||m.liquidity<MIN_SCOUT_LIQUIDITY)return null;
@@ -1207,7 +1226,7 @@ function compactSyncItems(items,limits=SYNC_LIMITS){
}
function saveState(st){localStorage.setItem(AGENTS_KEY,JSON.stringify(compactAgentStateForSync(st)));}
function loadSuggestions(){try{const s=localStorage.getItem(SUG_KEY);return s?JSON.parse(s):{date:null,suggestions:[]};}catch(e){return {date:null,suggestions:[]};}}
function saveSuggestions(sugs,marketCount=0){const p={date:todayStr(),generated_at:nowIso(),engine_version:SUGGESTION_ENGINE_VERSION,market_count:marketCount,suggestion_cap:SUGGESTION_TOTAL,suggestions:sugs};const compact=compactSuggestionsForSync(p);localStorage.setItem(SUG_KEY,JSON.stringify(compact));return compact;}
function saveSuggestions(sugs,marketCount=0,analyzedCount=null){const p={date:todayStr(),generated_at:nowIso(),engine_version:SUGGESTION_ENGINE_VERSION,market_count:marketCount,analyzed_count:analyzedCount==null?marketCount:analyzedCount,analysis_limit:MARKET_ANALYSIS_LIMIT,suggestion_cap:SUGGESTION_TOTAL,suggestions:sugs};const compact=compactSuggestionsForSync(p);localStorage.setItem(SUG_KEY,JSON.stringify(compact));return compact;}
function collectSyncItems(){const items={};SYNC_KEYS.forEach(k=>{const v=localStorage.getItem(k);if(v!=null)items[k]=v;});return compactSyncItems(items);}
function applySyncItems(items){
if(!items||typeof items!=="object")return false;
@@ -2031,11 +2050,13 @@ async function runDailyCycle(){
SNAP_TS=nowIso();
setStatus("fetching markets…",true);
const markets=await fetchMarkets(Infinity,100,count=>setStatus(`fetching all active markets (${count})…`,true));
const analysisMarkets=selectMarketsForAnalysis(markets);
setStatus(`selected top ${analysisMarkets.length.toLocaleString()} markets for analysis…`,true);
setStatus("checking real-world context…",true);
const realWorldSignals=await fetchRealWorldSignals(markets);
const realWorldSignals=await fetchRealWorldSignals(analysisMarkets);
setStatus("analyzing expected value…",true);
const sugs=generateSuggestions(markets,SUGGESTION_TOTAL,SUGGESTION_PER_CATEGORY,realWorldSignals);
saveSuggestions(sugs,markets.length);
const sugs=generateSuggestions(analysisMarkets,SUGGESTION_TOTAL,SUGGESTION_PER_CATEGORY,realWorldSignals);
saveSuggestions(sugs,markets.length,analysisMarkets.length);
st=loadState();
const emailOffsets=agentHistoryOffsets(st);
const focus=getFocus();
@@ -2428,9 +2449,11 @@ function renderSuggestions(){
const filtered=pool.slice(0,VISIBLE_SUGGESTIONS);
const buyCount=all.filter(s=>s.trade_ready).length,watchCount=all.length-buyCount;
const evAvg=all.length?Math.round(all.reduce((s,x)=>s+Number(x.evidence_score||0),0)/all.length*100):0;
const scanned=Number(data.market_count||0).toLocaleString();
const analyzed=Number(data.analyzed_count||data.market_count||0).toLocaleString();
$("focusNote").textContent=focus==="All"
? `Scanned ${Number(data.market_count||0).toLocaleString()} active markets and kept ${all.length} ideas (${buyCount} BUY, ${watchCount} WATCH). Showing ${filtered.length}; agents trade only EV+ ideas after liquidity, chase, and real-world evidence checks. Avg evidence ${evAvg}.`
: `Scanned ${Number(data.market_count||0).toLocaleString()} active markets. Showing ${filtered.length} of ${pool.length} ${focus} ideas; agents only open EV+ BUY ${focus} positions while this is selected.`;
? `Scanned ${scanned} active markets, analyzed the top ${analyzed} by activity/liquidity/gap, and kept ${all.length} ideas (${buyCount} BUY, ${watchCount} WATCH). Showing ${filtered.length}; agents trade only EV+ ideas after liquidity, chase, and real-world evidence checks. Avg evidence ${evAvg}.`
: `Scanned ${scanned} active markets and analyzed the top ${analyzed}. Showing ${filtered.length} of ${pool.length} ${focus} ideas; agents only open EV+ BUY ${focus} positions while this is selected.`;
if(!filtered.length){root.innerHTML=`<div class="empty" style="grid-column:1/-1">No ${esc(focus)} suggestions in this live batch.</div>`;return;}
root.innerHTML=filtered.map(s=>{
const col=catColor(s.category);