mirror of
https://github.com/theodore-song/polymarket-analyst.git
synced 2026-08-24 04:58:08 +00:00
Preserve learning and size verified bundles
This commit is contained in:
@@ -35,7 +35,7 @@ jobs:
|
|||||||
- run: node scripts/run-autonomous-cycle.mjs
|
- run: node scripts/run-autonomous-cycle.mjs
|
||||||
env:
|
env:
|
||||||
ARENA_URL: https://polymarket-site-eta.vercel.app
|
ARENA_URL: https://polymarket-site-eta.vercel.app
|
||||||
EXPECTED_BUILD: "115"
|
EXPECTED_BUILD: "116"
|
||||||
RUNTIME_BRANCH: runtime-state
|
RUNTIME_BRANCH: runtime-state
|
||||||
RUNTIME_STATE_PATH: runtime/state.json
|
RUNTIME_STATE_PATH: runtime/state.json
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ market snapshots. During an outage, cycles continue locally; cached entries are
|
|||||||
allowed for 90 minutes, older snapshots become mark-only, and all cached data
|
allowed for 90 minutes, older snapshots become mark-only, and all cached data
|
||||||
expires after 24 hours.
|
expires after 24 hours.
|
||||||
|
|
||||||
Build 115 targets five-minute slots with a serialized, self-chained GitHub Actions runtime.
|
Build 116 targets five-minute slots with a serialized, self-chained GitHub Actions runtime.
|
||||||
It continues from the previous agent snapshot and runs the next due paper cycle
|
It continues from the previous agent snapshot and runs the next due paper cycle
|
||||||
even when no browser is open. After each successful cycle, one repo-scoped
|
even when no browser is open. After each successful cycle, one repo-scoped
|
||||||
workflow dispatch waits for the next five-minute boundary; one concurrency group
|
workflow dispatch waits for the next five-minute boundary; one concurrency group
|
||||||
@@ -29,7 +29,10 @@ and the cron schedule remains as recovery. The runtime writes a
|
|||||||
sanitized snapshot to the `runtime-state` branch and `/api/state` uses that as a
|
sanitized snapshot to the `runtime-state` branch and `/api/state` uses that as a
|
||||||
read-only fallback while Neon or Vercel Blob is unavailable. The public snapshot
|
read-only fallback while Neon or Vercel Blob is unavailable. The public snapshot
|
||||||
contains only `pma_agents_v2` and `pma_suggestions_v5`, with suggestions capped at
|
contains only `pma_agents_v2` and `pma_suggestions_v5`, with suggestions capped at
|
||||||
300 to keep cross-device loads small. Paper accounts, passwords, email settings,
|
300 to keep cross-device loads small. The API preserves oldest-first pending
|
||||||
|
observations plus fee schedules, agent promotion scopes, and verified bundle
|
||||||
|
capacity from the bounded runtime instead of applying its older lossy compactor.
|
||||||
|
Paper accounts, passwords, email settings,
|
||||||
investment allocations, chat history, wallet information, and live-money
|
investment allocations, chat history, wallet information, and live-money
|
||||||
settings are explicitly excluded. While that fallback is active, ordinary
|
settings are explicitly excluded. While that fallback is active, ordinary
|
||||||
phones and computers are display-only and cannot fork the public portfolio with
|
phones and computers are display-only and cannot fork the public portfolio with
|
||||||
@@ -48,15 +51,18 @@ Polymarket event key. Related Ethereum or Bitcoin contracts cannot create
|
|||||||
several simultaneous copies of one move, and outcomes from the same underlying
|
several simultaneous copies of one move, and outcomes from the same underlying
|
||||||
three-hour shock window count as one learner event.
|
three-hour shock window count as one learner event.
|
||||||
|
|
||||||
Each Build 115 cycle also scans the 1,000 most-active Polymarket events for
|
Each Build 116 cycle also scans the 1,000 most-active Polymarket events for
|
||||||
complete negative-risk bundles and logically nested threshold or deadline
|
complete negative-risk bundles and logically nested threshold or deadline
|
||||||
pairs. Gamma's market-specific fee flag replaces the old blanket 0.5-cent fee
|
pairs. Gamma's market-specific fee flag replaces the old blanket 0.5-cent fee
|
||||||
reserve for markets declared fee-free. The closest 60 structures are then
|
reserve for markets declared fee-free. The closest 60 structures are then
|
||||||
repriced from batched CLOB asks at the equal-unit size needed for at least a $50
|
repriced from batched CLOB asks from the equal-unit size needed for at least a $50
|
||||||
paper order. The scanner applies each market's Gamma fee schedule at every
|
paper order up to a $400 verified-notional ceiling. The scanner applies each market's Gamma fee schedule at every
|
||||||
consumed ask level and checks the CLOB fee-rate endpoint for a matching enabled
|
consumed ask level and checks the CLOB fee-rate endpoint for a matching enabled
|
||||||
or fee-free state. Any opened position is capped to the exact equal-unit size
|
or fee-free state. Any opened position is capped to the exact equal-unit size
|
||||||
that passed this depth test. A bundle can enter Value Discipline only when that fee check
|
of the largest fill that stays profitable and passes this depth test; portfolio
|
||||||
|
cash, reserve, and 4% limits can reduce it further. Existing paper bundles are
|
||||||
|
never retroactively enlarged against depth their original simulated fill would
|
||||||
|
already have consumed. A bundle can enter Value Discipline only when that fee check
|
||||||
passes and the resulting worst-case payout clears both the three-tenths-cent
|
passes and the resulting worst-case payout clears both the three-tenths-cent
|
||||||
profit floor and the 0.15% return floor. Top-of-book gaps, missing books,
|
profit floor and the 0.15% return floor. Top-of-book gaps, missing books,
|
||||||
incomplete fee schedules, and unavailable fee verification remain audit-only.
|
incomplete fee schedules, and unavailable fee verification remain audit-only.
|
||||||
@@ -64,7 +70,7 @@ The Suggestions view stores scan, depth, fee, actionable, and closest
|
|||||||
executable-margin counts so an empty lane is evidence rather than an ambiguous
|
executable-margin counts so an empty lane is evidence rather than an ambiguous
|
||||||
failure.
|
failure.
|
||||||
|
|
||||||
Build 115 retains the directional learner's exact-fee policy, which replaced the blanket half-cent cost with
|
Build 116 retains the directional learner's exact-fee policy, which replaced the blanket half-cent cost with
|
||||||
the market's Gamma fee schedule at both the entry and future checkpoint, plus a
|
the market's Gamma fee schedule at both the entry and future checkpoint, plus a
|
||||||
separate half-cent round-trip slippage allowance. Fee-free markets pay only the
|
separate half-cent round-trip slippage allowance. Fee-free markets pay only the
|
||||||
slippage allowance; an unavailable fee schedule gets a conservative four-cent
|
slippage allowance; an unavailable fee schedule gets a conservative four-cent
|
||||||
@@ -80,7 +86,7 @@ directional evidence under fee policy 2 and keeps those lanes observation-only
|
|||||||
until current independent 24-hour and 72-hour cohorts pass the existing
|
until current independent 24-hour and 72-hour cohorts pass the existing
|
||||||
promotion gate.
|
promotion gate.
|
||||||
|
|
||||||
Build 115 retains Build 100's retirement of the old 3-6 day resolution-window
|
Build 116 retains Build 100's retirement of the old 3-6 day resolution-window
|
||||||
capital permission. That audit clustered confidence by event but still averaged
|
capital permission. That audit clustered confidence by event but still averaged
|
||||||
several correlated contracts inside each event, while production could choose
|
several correlated contracts inside each event, while production could choose
|
||||||
only one. The corrected replay chooses the highest-volume eligible contract per event and
|
only one. The corrected replay chooses the highest-volume eligible contract per event and
|
||||||
@@ -200,7 +206,7 @@ evidence proves an edge.
|
|||||||
|
|
||||||
Run `npm run evaluate:sports-favorites` for the retired pregame favorite audit.
|
Run `npm run evaluate:sports-favorites` for the retired pregame favorite audit.
|
||||||
Its 12-hour, 60%-75% cohort had positive point estimates but did not establish a
|
Its 12-hour, 60%-75% cohort had positive point estimates but did not establish a
|
||||||
reliable confidence bound, so Build 115 no longer allocates capital to that rule.
|
reliable confidence bound, so Build 116 no longer allocates capital to that rule.
|
||||||
|
|
||||||
Strategy 62 instead uses the exact-fee settlement calibration's three-day Sports
|
Strategy 62 instead uses the exact-fee settlement calibration's three-day Sports
|
||||||
NO cohort as a bounded paper exploration lane. The corrected 5,000-market run
|
NO cohort as a bounded paper exploration lane. The corrected 5,000-market run
|
||||||
|
|||||||
+14
-6
@@ -14,7 +14,7 @@ const PAPER_KEY = "pma_paper_accounts_v1";
|
|||||||
const LIVE_KEY = "pma_live_readiness_v1";
|
const LIVE_KEY = "pma_live_readiness_v1";
|
||||||
const AGENT_IDS = ["value", "momentum", "favorite", "longshot", "diversifier", "catalyst", "reversal", "breakout", "tailalpha", "conviction"];
|
const AGENT_IDS = ["value", "momentum", "favorite", "longshot", "diversifier", "catalyst", "reversal", "breakout", "tailalpha", "conviction"];
|
||||||
const LIMITS = { closed: 80, history: 160, snapshots: 240, suggestions: 900, paperHistory: 120, paperSnapshots: 120, audit: 120 };
|
const LIMITS = { closed: 80, history: 160, snapshots: 240, suggestions: 900, paperHistory: 120, paperSnapshots: 120, audit: 120 };
|
||||||
const SIGNAL_LEDGER_LIMITS = { pending: 300, outcomes: 500 };
|
const SIGNAL_LEDGER_LIMITS = { pending: 600, outcomes: 1000 };
|
||||||
const RUNTIME_ALLOWED_KEYS = new Set([AGENTS_KEY, SUG_KEY]);
|
const RUNTIME_ALLOWED_KEYS = new Set([AGENTS_KEY, SUG_KEY]);
|
||||||
|
|
||||||
function withBlobAuth(options = {}) {
|
function withBlobAuth(options = {}) {
|
||||||
@@ -200,8 +200,8 @@ async function latestVersionedStateBlob() {
|
|||||||
return readBlobJson(newest.pathname);
|
return readBlobJson(newest.pathname);
|
||||||
}
|
}
|
||||||
|
|
||||||
function cycleVersion(cycle = "") {
|
export function cycleVersion(cycle = "") {
|
||||||
const m = String(cycle).match(/\|v(\d+)$/);
|
const m = String(cycle).match(/\|[vs](\d+)$/);
|
||||||
return m ? Number(m[1]) : 0;
|
return m ? Number(m[1]) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,7 +261,7 @@ export function compactAgentState(st) {
|
|||||||
}
|
}
|
||||||
if (st.signal_ledger && typeof st.signal_ledger === "object") {
|
if (st.signal_ledger && typeof st.signal_ledger === "object") {
|
||||||
out.signal_ledger = {
|
out.signal_ledger = {
|
||||||
pending: Array.isArray(st.signal_ledger.pending) ? st.signal_ledger.pending.slice(-SIGNAL_LEDGER_LIMITS.pending) : [],
|
pending: Array.isArray(st.signal_ledger.pending) ? st.signal_ledger.pending.slice(0, SIGNAL_LEDGER_LIMITS.pending) : [],
|
||||||
outcomes: Array.isArray(st.signal_ledger.outcomes) ? st.signal_ledger.outcomes.slice(-SIGNAL_LEDGER_LIMITS.outcomes) : [],
|
outcomes: Array.isArray(st.signal_ledger.outcomes) ? st.signal_ledger.outcomes.slice(-SIGNAL_LEDGER_LIMITS.outcomes) : [],
|
||||||
expired_ungraded: Number(st.signal_ledger.expired_ungraded || 0),
|
expired_ungraded: Number(st.signal_ledger.expired_ungraded || 0),
|
||||||
};
|
};
|
||||||
@@ -280,15 +280,23 @@ export function compactSuggestion(s) {
|
|||||||
net_edge: s.net_edge, friction: s.friction, chase_penalty: s.chase_penalty,
|
net_edge: s.net_edge, friction: s.friction, chase_penalty: s.chase_penalty,
|
||||||
evidence_score: s.evidence_score, evidence_source_count: s.evidence_source_count, quality: s.quality,
|
evidence_score: s.evidence_score, evidence_source_count: s.evidence_source_count, quality: s.quality,
|
||||||
conviction: s.conviction, volume: s.volume, volume_24hr: s.volume_24hr, liquidity: s.liquidity,
|
conviction: s.conviction, volume: s.volume, volume_24hr: s.volume_24hr, liquidity: s.liquidity,
|
||||||
|
fees_enabled: s.fees_enabled, fee_schedule: s.fee_schedule,
|
||||||
spread: s.spread, price_change_1h: s.price_change_1h, price_change_1d: s.price_change_1d, price_change_1w: s.price_change_1w,
|
spread: s.spread, price_change_1h: s.price_change_1h, price_change_1d: s.price_change_1d, price_change_1w: s.price_change_1w,
|
||||||
momentum_strength: s.momentum_strength, signal_strength: s.signal_strength, signal_confidence: s.signal_confidence,
|
momentum_strength: s.momentum_strength, signal_strength: s.signal_strength, signal_confidence: s.signal_confidence,
|
||||||
signal_type: s.signal_type, trade_ready: s.trade_ready, entry_candidate: s.entry_candidate,
|
signal_type: s.signal_type, trade_ready: s.trade_ready, entry_candidate: s.entry_candidate,
|
||||||
audited_observation_only: s.audited_observation_only, adaptive_promotion: s.adaptive_promotion,
|
audited_observation_only: s.audited_observation_only, adaptive_promotion: s.adaptive_promotion,
|
||||||
|
promoted_for_agents: s.promoted_for_agents,
|
||||||
watch_only: s.watch_only, jump_risk: s.jump_risk, requires_live: s.requires_live,
|
watch_only: s.watch_only, jump_risk: s.jump_risk, requires_live: s.requires_live,
|
||||||
bundle_id: s.bundle_id, bundle_side: s.bundle_side, bundle_logic: s.bundle_logic, bundle_cost_per_unit: s.bundle_cost_per_unit,
|
bundle_id: s.bundle_id, bundle_side: s.bundle_side, bundle_logic: s.bundle_logic, bundle_cost_per_unit: s.bundle_cost_per_unit,
|
||||||
bundle_payout_per_unit: s.bundle_payout_per_unit, bundle_net_profit_per_unit: s.bundle_net_profit_per_unit,
|
bundle_payout_per_unit: s.bundle_payout_per_unit, bundle_net_profit_per_unit: s.bundle_net_profit_per_unit,
|
||||||
bundle_legs: s.bundle_legs,
|
bundle_legs: s.bundle_legs, depth_verified: s.depth_verified, fees_verified: s.fees_verified,
|
||||||
days_to_resolution: s.days_to_resolution, pilot_prior: s.pilot_prior,
|
fee_model: s.fee_model, execution_model: s.execution_model, execution_units: s.execution_units,
|
||||||
|
execution_notional: s.execution_notional, verification_status: s.verification_status,
|
||||||
|
days_to_resolution: s.days_to_resolution, end_date: s.end_date, game_start: s.game_start,
|
||||||
|
hours_to_start: s.hours_to_start, target_horizon_days: s.target_horizon_days,
|
||||||
|
resolution_week_strategy_version: s.resolution_week_strategy_version,
|
||||||
|
sports_contest_strategy_version: s.sports_contest_strategy_version, entry_fee: s.entry_fee,
|
||||||
|
pilot_prior: s.pilot_prior,
|
||||||
shock_move_1h: s.shock_move_1h, shock_prior_move_1h: s.shock_prior_move_1h, shock_move_3h: s.shock_move_3h,
|
shock_move_1h: s.shock_move_1h, shock_prior_move_1h: s.shock_prior_move_1h, shock_move_3h: s.shock_move_3h,
|
||||||
shock_observed_at: s.shock_observed_at, shock_strategy_version: s.shock_strategy_version,
|
shock_observed_at: s.shock_observed_at, shock_strategy_version: s.shock_strategy_version,
|
||||||
drivers: s.drivers, rationale: s.rationale,
|
drivers: s.drivers, rationale: s.rationale,
|
||||||
|
|||||||
+56
-37
@@ -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 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>
|
||||||
<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 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 ============ -->
|
<!-- ============ OVERVIEW ============ -->
|
||||||
<section class="tabpanel" data-tab="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>
|
</section>
|
||||||
|
|
||||||
<footer>
|
<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>
|
<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,7 +774,7 @@ 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 = 115;
|
const BUILD_VERSION = 116;
|
||||||
const AGENT_LEARNING_VERSION = 3;
|
const AGENT_LEARNING_VERSION = 3;
|
||||||
const SUGGESTION_ENGINE_VERSION = 62;
|
const SUGGESTION_ENGINE_VERSION = 62;
|
||||||
const MAKER_STRATEGY_VERSION = 3;
|
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;
|
const notionalUnits=Math.ceil(((BUNDLE_MIN_NOTIONAL+0.01)/cost)*100)/100;
|
||||||
return +Math.max(BUNDLE_MIN_UNITS,baseline,notionalUnits).toFixed(2);
|
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&"e.depth_verified&"e.legs.every(leg=>leg.fee_config_valid)
|
||||||
|
&"e.profit>=NEG_RISK_MIN_NET_PROFIT&"e.net_return>=NEG_RISK_MIN_NET_RETURN
|
||||||
|
&"e.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){
|
async function fetchBundleBooks(tokenIds){
|
||||||
const books=new Map(),unique=[...new Set((tokenIds||[]).map(String).filter(Boolean))];
|
const books=new Map(),unique=[...new Set((tokenIds||[]).map(String).filter(Boolean))];
|
||||||
for(let index=0;index<unique.length;index+=BUNDLE_BOOK_BATCH_SIZE){
|
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 tokenIds=shortlist.flatMap(candidate=>(candidate.bundle_legs||[]).map(leg=>leg.token_id));
|
||||||
const books=await fetchBundleBooks(tokenIds),depthChecked=shortlist.map(candidate=>{
|
const books=await fetchBundleBooks(tokenIds),depthChecked=shortlist.map(candidate=>{
|
||||||
const estimatedCost=Number(candidate.bundle_cost_per_unit),requiredUnits=bundleMinimumExecutionUnits(Math.max(estimatedCost,0.01));
|
const estimatedCost=Number(candidate.bundle_cost_per_unit),requiredUnits=bundleMinimumExecutionUnits(Math.max(estimatedCost,0.01));
|
||||||
const legs=(candidate.bundle_legs||[]).map(leg=>{
|
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 book=books.get(String(leg.token_id||"")),minimum=Number(book&&book.min_order_size||0),units=Math.max(requiredUnits,minimum);
|
const quote=maximizeBundleExecution(candidate,books,minimumUnits),cost=quote.cost,profit=quote.profit,netReturn=quote.net_return;
|
||||||
const executable=bundleExecutableLeg(book,units,leg.fee_schedule);
|
return Object.assign({},candidate,{bundle_legs:quote.legs,execution_units:quote.units,execution_notional:Number.isFinite(quote.notional)?+quote.notional.toFixed(2):null,
|
||||||
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,
|
|
||||||
bundle_cost_per_unit:Number.isFinite(cost)?+cost.toFixed(6):null,bundle_net_profit_per_unit:Number.isFinite(profit)?+profit.toFixed(6):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,
|
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,
|
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:depthVerified?"depth-verified":"insufficient-depth"});
|
execution_model:"live-order-book-vwap",verification_status:quote.depth_verified?"depth-verified":"insufficient-depth"});
|
||||||
});
|
});
|
||||||
const potentiallyActionable=depthChecked.filter(candidate=>candidate.depth_verified
|
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
|
&&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_FEE_CONCURRENCY=8;
|
||||||
const BUNDLE_MIN_NOTIONAL=50;
|
const BUNDLE_MIN_NOTIONAL=50;
|
||||||
const BUNDLE_MIN_UNITS=5;
|
const BUNDLE_MIN_UNITS=5;
|
||||||
|
const BUNDLE_MAX_VERIFIED_NOTIONAL=400;
|
||||||
const SPORTS_FAVORITE_MIN_ENTRY=0.03;
|
const SPORTS_FAVORITE_MIN_ENTRY=0.03;
|
||||||
const SPORTS_FAVORITE_MAX_ENTRY=0.97;
|
const SPORTS_FAVORITE_MAX_ENTRY=0.97;
|
||||||
const SPORTS_FAVORITE_TARGET_LEAD_HOURS=72;
|
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},
|
{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 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)=>({
|
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"]`,
|
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,
|
||||||
@@ -7491,6 +7506,10 @@ function runEngineSelfTest(){
|
|||||||
&&zeroFeeBundleSuggestion.bundle_cost_per_unit===0.95&&zeroFeeBundleSuggestion.bundle_net_profit_per_unit===0.05),
|
&&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,
|
appliesPublishedFeeCurve:bundleFeePerShare({rate:0.07,exponent:1,takerOnly:true},0.5)===0.0175,
|
||||||
depthVwapConsumesMultipleAskLevels:depthVwapFixture===0.396,
|
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,
|
liveRepricingRoundsUpToMinimumNotional:repricedBoundaryUnits===50.21&&repricedBoundaryUnits*0.996041>=BUNDLE_MIN_NOTIONAL+0.009,
|
||||||
repricedMinimumNotionalOpensAtomically:Boolean(repricedBoundaryOpen&&repricedBoundaryBook.positions.length===2
|
repricedMinimumNotionalOpensAtomically:Boolean(repricedBoundaryOpen&&repricedBoundaryBook.positions.length===2
|
||||||
&&repricedBoundaryOpen.cost>=BUNDLE_MIN_NOTIONAL),
|
&&repricedBoundaryOpen.cost>=BUNDLE_MIN_NOTIONAL),
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ async function main() {
|
|||||||
const branch = process.env.RUNTIME_BRANCH || "runtime-state";
|
const branch = process.env.RUNTIME_BRANCH || "runtime-state";
|
||||||
const pathname = process.env.RUNTIME_STATE_PATH || "runtime/state.json";
|
const pathname = process.env.RUNTIME_STATE_PATH || "runtime/state.json";
|
||||||
const arenaUrl = (process.env.ARENA_URL || "https://polymarket-site-eta.vercel.app").replace(/\/$/, "");
|
const arenaUrl = (process.env.ARENA_URL || "https://polymarket-site-eta.vercel.app").replace(/\/$/, "");
|
||||||
const expectedBuild = Number(required("EXPECTED_BUILD", "115"));
|
const expectedBuild = Number(required("EXPECTED_BUILD", "116"));
|
||||||
await ensureRuntimeBranch(repository, branch);
|
await ensureRuntimeBranch(repository, branch);
|
||||||
const prior = await readRuntimeFile(repository, branch, pathname);
|
const prior = await readRuntimeFile(repository, branch, pathname);
|
||||||
if (prior.snapshot) validateRuntimeSnapshot(prior.snapshot, 0, { allowIncomplete: true });
|
if (prior.snapshot) validateRuntimeSnapshot(prior.snapshot, 0, { allowIncomplete: true });
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const resolutionAudit = JSON.parse(fs.readFileSync(new URL("../research/resoluti
|
|||||||
const sportsContestAudit = JSON.parse(fs.readFileSync(new URL("../research/sports-contest-no-exploration-audit.json", import.meta.url), "utf8"));
|
const sportsContestAudit = JSON.parse(fs.readFileSync(new URL("../research/sports-contest-no-exploration-audit.json", import.meta.url), "utf8"));
|
||||||
const build = Number(index.match(/const BUILD_VERSION = (\d+);/)?.[1]);
|
const build = Number(index.match(/const BUILD_VERSION = (\d+);/)?.[1]);
|
||||||
|
|
||||||
assert.equal(build, 115);
|
assert.equal(build, 116);
|
||||||
assert.deepEqual([...ALLOWED_RUNTIME_KEYS].sort(), ["pma_agents_v2", "pma_suggestions_v5"]);
|
assert.deepEqual([...ALLOWED_RUNTIME_KEYS].sort(), ["pma_agents_v2", "pma_suggestions_v5"]);
|
||||||
assert.match(index, /function collectPublicRuntimeItems\(\)/);
|
assert.match(index, /function collectPublicRuntimeItems\(\)/);
|
||||||
assert.match(index, /const PUBLIC_RUNTIME_KEYS=Object\.freeze\(\[AGENTS_KEY,SUG_KEY\]\)/);
|
assert.match(index, /const PUBLIC_RUNTIME_KEYS=Object\.freeze\(\[AGENTS_KEY,SUG_KEY\]\)/);
|
||||||
@@ -40,7 +40,7 @@ assert.match(api, /Buffer\.from\(file\.content/);
|
|||||||
assert.match(api, /searchParams\.set\("runtime", `\$\{Date\.now\(\)\}/);
|
assert.match(api, /searchParams\.set\("runtime", `\$\{Date\.now\(\)\}/);
|
||||||
assert.match(workflow, /cron: "2,7,12,17,22,27,32,37,42,47,52,57 \* \* \* \*"/);
|
assert.match(workflow, /cron: "2,7,12,17,22,27,32,37,42,47,52,57 \* \* \* \*"/);
|
||||||
assert.match(workflow, /contents: write/);
|
assert.match(workflow, /contents: write/);
|
||||||
assert.match(workflow, /EXPECTED_BUILD: "115"/);
|
assert.match(workflow, /EXPECTED_BUILD: "116"/);
|
||||||
assert.match(workflow, /actions: write/);
|
assert.match(workflow, /actions: write/);
|
||||||
assert.match(workflow, /cancel-in-progress: false/);
|
assert.match(workflow, /cancel-in-progress: false/);
|
||||||
assert.match(workflow, /next=\$\(\( \(now \/ 300 \+ 1\) \* 300 \+ 15 \)\)/);
|
assert.match(workflow, /next=\$\(\( \(now \/ 300 \+ 1\) \* 300 \+ 15 \)\)/);
|
||||||
@@ -54,6 +54,10 @@ assert.match(index, /const BUNDLE_DEPTH_CANDIDATE_LIMIT=60;/);
|
|||||||
assert.match(index, /bundleRequiresDepthVerification:true/);
|
assert.match(index, /bundleRequiresDepthVerification:true/);
|
||||||
assert.match(index, /bundleRequiresClobFeeVerification:true/);
|
assert.match(index, /bundleRequiresClobFeeVerification:true/);
|
||||||
assert.match(index, /function bundleExecutableLeg\(book,units,feeSchedule\)/);
|
assert.match(index, /function bundleExecutableLeg\(book,units,feeSchedule\)/);
|
||||||
|
assert.match(index, /function maximizeBundleExecution\(candidate,books,minimumUnits\)/);
|
||||||
|
assert.match(index, /const BUNDLE_MAX_VERIFIED_NOTIONAL=400;/);
|
||||||
|
assert.match(index, /sizesToLargestVerifiedProfitableFill:/);
|
||||||
|
assert.match(index, /stopsSizingAtShallowestBundleLeg:/);
|
||||||
assert.match(index, /!s\.depth_verified\|\|!s\.fees_verified\|\|s\.verification_status!=="executable"/);
|
assert.match(index, /!s\.depth_verified\|\|!s\.fees_verified\|\|s\.verification_status!=="executable"/);
|
||||||
assert.match(runner, /MAX_STATE_BYTES = 900_000/);
|
assert.match(runner, /MAX_STATE_BYTES = 900_000/);
|
||||||
assert.equal(resolutionAudit.strategy, "resolution-window-no-50-55-forward-shadow-v3");
|
assert.equal(resolutionAudit.strategy, "resolution-window-no-50-55-forward-shadow-v3");
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
import assert from "node:assert/strict";
|
import assert from "node:assert/strict";
|
||||||
import { databaseConnectionDiagnostics, databaseUrl, databaseUrls, normalizeDatabaseUrl } from "../lib/db.js";
|
import { databaseConnectionDiagnostics, databaseUrl, databaseUrls, normalizeDatabaseUrl } from "../lib/db.js";
|
||||||
import { compactAgentState, compactSuggestion, providerErrorCode, sanitizeGithubRuntimeState } from "../api/state.js";
|
import { compactAgentState, compactSuggestion, cycleVersion, providerErrorCode, sanitizeGithubRuntimeState } from "../api/state.js";
|
||||||
|
|
||||||
assert.equal(normalizeDatabaseUrl("psql 'postgresql://user:pass@example.test/db?sslmode=require'"),
|
assert.equal(normalizeDatabaseUrl("psql 'postgresql://user:pass@example.test/db?sslmode=require'"),
|
||||||
"postgresql://user:pass@example.test/db?sslmode=require");
|
"postgresql://user:pass@example.test/db?sslmode=require");
|
||||||
assert.equal(normalizeDatabaseUrl('"postgres://user:pass@example.test/db"'), "postgres://user:pass@example.test/db");
|
assert.equal(normalizeDatabaseUrl('"postgres://user:pass@example.test/db"'), "postgres://user:pass@example.test/db");
|
||||||
assert.equal(normalizeDatabaseUrl("DATABASE_URL=postgresql://user:pass@example.test/db"),
|
assert.equal(normalizeDatabaseUrl("DATABASE_URL=postgresql://user:pass@example.test/db"),
|
||||||
"postgresql://user:pass@example.test/db");
|
"postgresql://user:pass@example.test/db");
|
||||||
|
assert.equal(cycleVersion("2026-08-21T20|v59"), 59);
|
||||||
|
assert.equal(cycleVersion("2026-08-21T20:05|s62"), 62);
|
||||||
|
assert.equal(cycleVersion("2026-08-21T20:05"), 0);
|
||||||
|
|
||||||
const originalDatabaseUrl = process.env.DATABASE_URL;
|
const originalDatabaseUrl = process.env.DATABASE_URL;
|
||||||
const originalNeonUrl = process.env.NEON_DATABASE_URL;
|
const originalNeonUrl = process.env.NEON_DATABASE_URL;
|
||||||
@@ -32,6 +35,9 @@ const compacted = compactSuggestion({
|
|||||||
entry_candidate: true, adaptive_promotion: false, requires_live: true, bundle_id: "bundle:1:yes",
|
entry_candidate: true, adaptive_promotion: false, requires_live: true, bundle_id: "bundle:1:yes",
|
||||||
bundle_side: "YES", bundle_logic: "threshold-dominance", bundle_cost_per_unit: 0.95, bundle_payout_per_unit: 1,
|
bundle_side: "YES", bundle_logic: "threshold-dominance", bundle_cost_per_unit: 0.95, bundle_payout_per_unit: 1,
|
||||||
bundle_net_profit_per_unit: 0.05, bundle_legs: [{ market_id: "1", side: "YES" }],
|
bundle_net_profit_per_unit: 0.05, bundle_legs: [{ market_id: "1", side: "YES" }],
|
||||||
|
fees_enabled: false, fee_schedule: { rate: 0, exponent: 1, takerOnly: true },
|
||||||
|
depth_verified: true, fees_verified: true, fee_model: "verified-market-specific", execution_model: "live-order-book-vwap",
|
||||||
|
execution_units: 250, execution_notional: 237.5, verification_status: "executable", promoted_for_agents: ["value"],
|
||||||
});
|
});
|
||||||
assert.equal(compacted.signal_type, "bundle-arb");
|
assert.equal(compacted.signal_type, "bundle-arb");
|
||||||
assert.equal(compacted.entry_candidate, true);
|
assert.equal(compacted.entry_candidate, true);
|
||||||
@@ -39,6 +45,10 @@ assert.equal(compacted.requires_live, true);
|
|||||||
assert.equal(compacted.bundle_side, "YES");
|
assert.equal(compacted.bundle_side, "YES");
|
||||||
assert.equal(compacted.bundle_logic, "threshold-dominance");
|
assert.equal(compacted.bundle_logic, "threshold-dominance");
|
||||||
assert.equal(compacted.bundle_legs.length, 1);
|
assert.equal(compacted.bundle_legs.length, 1);
|
||||||
|
assert.equal(compacted.fee_schedule.rate, 0);
|
||||||
|
assert.equal(compacted.execution_units, 250);
|
||||||
|
assert.equal(compacted.verification_status, "executable");
|
||||||
|
assert.deepEqual(compacted.promoted_for_agents, ["value"]);
|
||||||
|
|
||||||
const compactedShock = compactSuggestion({
|
const compactedShock = compactSuggestion({
|
||||||
market_id: "shock:1", event_key: "event:1", side: "NO", signal_type: "shock-fade-shadow",
|
market_id: "shock:1", event_key: "event:1", side: "NO", signal_type: "shock-fade-shadow",
|
||||||
@@ -64,6 +74,20 @@ assert.equal(compactedState.signal_ledger.expired_ungraded, 7);
|
|||||||
assert.equal(compactedState.agents.reversal.shock_fade_shadows[0].shock_strategy_version, 3);
|
assert.equal(compactedState.agents.reversal.shock_fade_shadows[0].shock_strategy_version, 3);
|
||||||
assert.equal(compactedState.agents.reversal.shock_fade_outcomes[0].net_return, 0.08);
|
assert.equal(compactedState.agents.reversal.shock_fade_outcomes[0].net_return, 0.08);
|
||||||
|
|
||||||
|
const ledgerOrder = compactAgentState({
|
||||||
|
agents: {},
|
||||||
|
signal_ledger: {
|
||||||
|
pending: Array.from({ length: 650 }, (_, i) => ({ key: `pending-${i}` })),
|
||||||
|
outcomes: Array.from({ length: 1050 }, (_, i) => ({ key: `outcome-${i}` })),
|
||||||
|
},
|
||||||
|
}).signal_ledger;
|
||||||
|
assert.equal(ledgerOrder.pending.length, 600);
|
||||||
|
assert.equal(ledgerOrder.pending[0].key, "pending-0");
|
||||||
|
assert.equal(ledgerOrder.pending.at(-1).key, "pending-599");
|
||||||
|
assert.equal(ledgerOrder.outcomes.length, 1000);
|
||||||
|
assert.equal(ledgerOrder.outcomes[0].key, "outcome-50");
|
||||||
|
assert.equal(ledgerOrder.outcomes.at(-1).key, "outcome-1049");
|
||||||
|
|
||||||
const publicAgents = Object.fromEntries([
|
const publicAgents = Object.fromEntries([
|
||||||
"value", "momentum", "favorite", "longshot", "diversifier", "catalyst", "reversal", "breakout", "tailalpha", "conviction",
|
"value", "momentum", "favorite", "longshot", "diversifier", "catalyst", "reversal", "breakout", "tailalpha", "conviction",
|
||||||
].map(id => [id, { cash: 10000, positions: [], closed: [], history: [], snapshots: [] }]));
|
].map(id => [id, { cash: 10000, positions: [], closed: [], history: [], snapshots: [] }]));
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const CACHE_NAME = "polymarket-arena-build-115";
|
const CACHE_NAME = "polymarket-arena-build-116";
|
||||||
const APP_SHELL = ["/", "/index.html", "/personal.html", "/cycle-worker.js"];
|
const APP_SHELL = ["/", "/index.html", "/personal.html", "/cycle-worker.js"];
|
||||||
|
|
||||||
self.addEventListener("install", event => {
|
self.addEventListener("install", event => {
|
||||||
|
|||||||
Reference in New Issue
Block a user