-
The Equity Race
+
-
Past week is a day-by-day backtest: agents re-ran their strategy on each day's real historical prices; whales are replayed from their on-chain trade history. (Volume/liquidity signals use current values — Polymarket doesn't expose historical volume.) Live tracking begins today.
+
Use the range buttons to zoom from one week to all history. New live points are added whenever you click "Run cycle"; the dashed line tracks the average agent return.
Top Picks Today highest conviction
@@ -308,10 +313,10 @@ footer{margin-top:34px;padding-top:22px;border-top:1px solid var(--border);color
🏆 Leaderboard
-
Equity Race — all agents $10,000 start each
+
-
Past week is a backtest — current holdings marked against real Polymarket price history. Live tracking takes over from today.
+
Past week is a backtest. After that, each manual or daily run adds another return snapshot for every agent.
@@ -383,6 +388,7 @@ const SUG_KEY = "pma_suggestions_v2";
const FOCUS_KEY = "pma_focus_v1";
const VIEW_KEY = "pma_view_v1";
const PF_SORT_KEY = "pma_portfolio_sort_v1";
+const CHART_RANGE_KEY = "pma_chart_range_v1";
const CATEGORIES = ["All","Politics","Sports","Crypto","Economy","Pop Culture","Other"];
const CAT_COLORS = {Politics:"#fb7185",Sports:"#34d399",Crypto:"#fbbf24",Economy:"#7c8cff",
"Pop Culture":"#c77dff",Other:"#94a1bb",All:"#7c8cff",Copy:"#22d3ee"};
@@ -437,6 +443,7 @@ const signClass = (n) => (n>0?"pos-val":n<0?"neg-val":"");
const todayStr = () => new Date().toISOString().slice(0,10);
const nowIso = () => new Date().toISOString();
let SIM_DAY = null; // set during backtest so logs/snapshots use the simulated date
+let SNAP_TS = null; // set during a live cycle so every agent gets the same chart x-value
const logDay = () => SIM_DAY || todayStr();
function toast(msg){
let t=document.querySelector(".toast");
@@ -645,11 +652,11 @@ function openPositions(p,cfg,rankedSugs,focus){
}
function recordSnapshot(p){
const eq=equity(p);
- const snap={date:logDay(),timestamp:(SIM_DAY?new Date(SIM_DAY+"T12:00:00Z").toISOString():nowIso()),cash:+p.cash.toFixed(2),
+ const snap={date:logDay(),timestamp:(SIM_DAY?new Date(SIM_DAY+"T12:00:00Z").toISOString():(SNAP_TS||nowIso())),cash:+p.cash.toFixed(2),
equity:+eq.toFixed(2),pnl:+(eq-p.starting_balance).toFixed(2),
return_pct:+((eq/p.starting_balance-1)*100).toFixed(2),open_positions:p.positions.length};
- p.snapshots=p.snapshots.filter(s=>s.date!==snap.date);
- p.snapshots.push(snap);p.snapshots.sort((a,b)=>a.date
s.date!==snap.date):p.snapshots.filter(s=>s.timestamp!==snap.timestamp);
+ p.snapshots.push(snap);p.snapshots.sort((a,b)=>new Date(a.timestamp||a.date)-new Date(b.timestamp||b.date));
}
/* ---------- Copy-trading: Polymarket leaders ---------- */
const hasAsset=(p,a)=>p.positions.some(x=>x.asset===a);
@@ -882,50 +889,53 @@ async function backtestWeek(st){
}
async function runDailyCycle(){
+ SNAP_TS=nowIso();
setStatus("fetching markets…",true);
- const markets=await fetchMarkets(4,100);
- setStatus("analyzing…",true);
- const sugs=generateSuggestions(markets,12);
- saveSuggestions(sugs);
- const st=loadState();
- const focus=getFocus();
- // Price map for suggestion-market positions (strategy + copycat only).
- const ids=new Set();
- AGENTS.filter(a=>a.kind==="strategy"||a.kind==="copycat").forEach(a=>
- (st.agents[a.id].positions||[]).forEach(pos=>{if(pos.market_id)ids.add(pos.market_id);}));
- setStatus("marking positions…",true);
- const priceMap={};
- for(const id of ids){priceMap[id]=await fetchMarketPrice(id);}
- // 1) in-house strategy agents
- setStatus("strategy agents trading…",true);
- for(const cfg of AGENTS.filter(a=>a.kind==="strategy")){
- const p=st.agents[cfg.id];
- markToMarket(p,priceMap);
- openPositions(p,cfg,cfg.rank(sugs),focus);
- recordSnapshot(p);
- }
- // 2) copycat shadows the leading strategy agent
- const stratBoard=AGENTS.filter(a=>a.kind==="strategy")
- .map(a=>({id:a.id,eq:equity(st.agents[a.id])})).sort((x,y)=>y.eq-x.eq);
- st.copycatLeader=stratBoard[0].id;
- runCopycat(st.agents["copycat"],st.agents[st.copycatLeader],priceMap);
- // 3) whale-copy agents mirror top Polymarket traders
- if(AGENTS.some(a=>a.kind==="whale"&&!st.whales[a.id])){
- setStatus("finding top Polymarket traders…",true);
- const picked=await discoverWhales();
- AGENTS.filter(a=>a.kind==="whale").forEach(a=>{if(!st.whales[a.id]&&picked[a.slot])st.whales[a.id]=picked[a.slot];});
- }
- for(const a of AGENTS.filter(x=>x.kind==="whale")){
- const wh=st.whales[a.id];
- if(!wh){recordSnapshot(st.agents[a.id]);continue;}
- setStatus(`copying ${wh.name}…`,true);
- try{await runWhaleAgent(st.agents[a.id],wh.wallet);}
- catch(e){recordSnapshot(st.agents[a.id]);}
- }
- st.date=todayStr();st.last_run=nowIso();
- saveState(st);
- setStatus("up to date",false);
- return {suggestions:sugs.length};
+ try{
+ const markets=await fetchMarkets(4,100);
+ setStatus("analyzing…",true);
+ const sugs=generateSuggestions(markets,12);
+ saveSuggestions(sugs);
+ const st=loadState();
+ const focus=getFocus();
+ // Price map for suggestion-market positions (strategy + copycat only).
+ const ids=new Set();
+ AGENTS.filter(a=>a.kind==="strategy"||a.kind==="copycat").forEach(a=>
+ (st.agents[a.id].positions||[]).forEach(pos=>{if(pos.market_id)ids.add(pos.market_id);}));
+ setStatus("marking positions…",true);
+ const priceMap={};
+ for(const id of ids){priceMap[id]=await fetchMarketPrice(id);}
+ // 1) in-house strategy agents
+ setStatus("strategy agents trading…",true);
+ for(const cfg of AGENTS.filter(a=>a.kind==="strategy")){
+ const p=st.agents[cfg.id];
+ markToMarket(p,priceMap);
+ openPositions(p,cfg,cfg.rank(sugs),focus);
+ recordSnapshot(p);
+ }
+ // 2) copycat shadows the leading strategy agent
+ const stratBoard=AGENTS.filter(a=>a.kind==="strategy")
+ .map(a=>({id:a.id,eq:equity(st.agents[a.id])})).sort((x,y)=>y.eq-x.eq);
+ st.copycatLeader=stratBoard[0].id;
+ runCopycat(st.agents["copycat"],st.agents[st.copycatLeader],priceMap);
+ // 3) whale-copy agents mirror top Polymarket traders
+ if(AGENTS.some(a=>a.kind==="whale"&&!st.whales[a.id])){
+ setStatus("finding top Polymarket traders…",true);
+ const picked=await discoverWhales();
+ AGENTS.filter(a=>a.kind==="whale").forEach(a=>{if(!st.whales[a.id]&&picked[a.slot])st.whales[a.id]=picked[a.slot];});
+ }
+ for(const a of AGENTS.filter(x=>x.kind==="whale")){
+ const wh=st.whales[a.id];
+ if(!wh){recordSnapshot(st.agents[a.id]);continue;}
+ setStatus(`copying ${wh.name}…`,true);
+ try{await runWhaleAgent(st.agents[a.id],wh.wallet);}
+ catch(e){recordSnapshot(st.agents[a.id]);}
+ }
+ st.date=todayStr();st.last_run=SNAP_TS;
+ saveState(st);
+ setStatus("up to date",false);
+ return {suggestions:sugs.length};
+ }finally{SNAP_TS=null;}
}
/* ---------- Leaderboard helpers ---------- */
@@ -1022,26 +1032,71 @@ function renderLeaderboard(){
});
drawCombo("chart2","comboLegend2");
}
+const CHART_RANGES=[
+ {id:"1w",label:"1W",days:7},
+ {id:"1m",label:"1M",days:30},
+ {id:"3m",label:"3M",days:90},
+ {id:"6m",label:"6M",days:180},
+ {id:"1y",label:"1Y",days:365},
+ {id:"5y",label:"5Y",days:1825},
+ {id:"all",label:"ALL",days:null},
+];
+function chartRange(){const r=localStorage.getItem(CHART_RANGE_KEY)||"1w";return CHART_RANGES.some(x=>x.id===r)?r:"1w";}
+function renderChartRanges(){
+ const active=chartRange();
+ document.querySelectorAll("[data-chart-ranges]").forEach(root=>{
+ root.innerHTML=CHART_RANGES.map(r=>`${r.label} `).join("");
+ });
+ document.querySelectorAll(".rangebtn").forEach(btn=>btn.onclick=()=>{localStorage.setItem(CHART_RANGE_KEY,btn.dataset.range);renderAll();});
+}
+const snapTime=(s)=>new Date(s.timestamp||`${s.date}T12:00:00Z`).getTime();
+function rangeFilteredTimes(times){
+ const range=CHART_RANGES.find(r=>r.id===chartRange())||CHART_RANGES[0];
+ if(!range.days)return times;
+ const newest=Math.max(...times);
+ const cutoff=newest-range.days*86400000;
+ const filtered=times.filter(t=>t>=cutoff);
+ return filtered.length?filtered:times.slice(-1);
+}
function drawCombo(svgId,legendId){
const st=loadState();
- const series=AGENTS.map(c=>({c,snaps:(st.agents[c.id]&&st.agents[c.id].snapshots)||[]}));
- const allDates=[...new Set(series.flatMap(s=>s.snaps.map(x=>x.date)))].sort();
+ renderChartRanges();
+ const series=AGENTS.map(c=>({c,snaps:((st.agents[c.id]&&st.agents[c.id].snapshots)||[])
+ .filter(s=>Number.isFinite(snapTime(s))).sort((a,b)=>snapTime(a)-snapTime(b))}));
+ const allTimes=rangeFilteredTimes([...new Set(series.flatMap(s=>s.snaps.map(snapTime)))].sort((a,b)=>a-b));
const svg=$(svgId); if(!svg)return;
- if(!allDates.length){svg.innerHTML="";if($(legendId))$(legendId).innerHTML=`No history yet — click "Run cycle". `;return;}
- const W=600,H=240,pad=10; const vals=[STARTING_BALANCE];
- const lines=series.map(s=>{let last=STARTING_BALANCE;const pts=allDates.map(d=>{const snap=s.snaps.find(x=>x.date===d);if(snap)last=snap.equity;vals.push(last);return last;});return {c:s.c,pts};});
- const min=Math.min(...vals)*0.999,max=Math.max(...vals)*1.001,span=(max-min)||1;
- const x=i=>allDates.length===1?W/2:pad+(i/(allDates.length-1))*(W-2*pad);
+ if(!allTimes.length){svg.innerHTML="";if($(legendId))$(legendId).innerHTML=`No history yet — click "Run cycle". `;return;}
+ const W=600,H=240,pad=14; const vals=[0];
+ const lines=series.map(s=>{
+ let last=0,idx=0;
+ const pts=allTimes.map(t=>{
+ while(idx+(lines.reduce((sum,l)=>sum+l.pts[i],0)/Math.max(1,lines.length)).toFixed(2));
+ vals.push(...avgPts);
+ const min=Math.min(...vals,0),max=Math.max(...vals,0),span=(max-min)||1;
+ const x=i=>allTimes.length===1?W/2:pad+(i/(allTimes.length-1))*(W-2*pad);
const y=v=>H-pad-((v-min)/span)*(H-2*pad);
- let inner="";
+ const zeroY=y(0).toFixed(1);
+ let inner=` `;
for(const ln of lines){
const d=ln.pts.map((v,i)=>`${i===0?"M":"L"}${x(i).toFixed(1)},${y(v).toFixed(1)}`).join(" ");
- const dot=allDates.length===1?` `:"";
+ const dot=allTimes.length===1?` `:"";
inner+=` ${dot}`;
}
+ const avgD=avgPts.map((v,i)=>`${i===0?"M":"L"}${x(i).toFixed(1)},${y(v).toFixed(1)}`).join(" ");
+ inner+=` `;
svg.innerHTML=inner;
if($(legendId)){
- $(legendId).innerHTML=board().map(r=>` ${r.c.emoji} ${r.c.name} ${fmtPct(r.ret)} `).join("");
+ const b=board();const avg=b.reduce((s,r)=>s+r.ret,0)/b.length;
+ $(legendId).innerHTML=` Average ${fmtPct(avg)} `+
+ b.map(r=>` ${r.c.emoji} ${r.c.name} ${fmtPct(r.ret)} `).join("");
}
}
function renderFilterBar(all){