polly-gamba 1.0.34 → 1.0.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/claude-trader.js +1 -1
- package/dist/lib/paper-trade.js +1 -1
- package/dist/mcp-server.js +7 -5
- package/dist/position-monitor.js +21 -6
- package/dist/test/stress.js +24 -0
- package/package.json +1 -1
- package/service.log +334 -0
- package/src/position-monitor.ts +21 -6
- package/src/test/stress.ts +33 -0
package/dist/claude-trader.js
CHANGED
|
@@ -115,7 +115,7 @@ RULES:
|
|
|
115
115
|
|
|
116
116
|
## POSITION DISCIPLINE:
|
|
117
117
|
- Max $100 per market (20% of $500 budget). The MCP enforces this — don't fight it.
|
|
118
|
-
- To add to an existing position with the SAME outcome: (1) you MUST cite a specific new catalyst (news published in last 24h, not price movement), AND (2) the current price must be ≥20% below your last entry price (e.g. if you bought YES at 0.15, new entry only valid at ≤0.12). The MCP enforces this — attempts at a smaller discount will be rejected. Price dipping alone is NOT a catalyst. New information is a catalyst.
|
|
118
|
+
- To add to an existing position with the SAME outcome: (1) you MUST cite a specific new catalyst (news published in last 24h, not price movement), AND (2) the current price must be ≥20% below your last entry price (e.g. if you bought YES at 0.15, new entry only valid at ≤0.12). The MCP enforces this — attempts at a smaller discount will be rejected. Price dipping alone is NOT a catalyst. New information is a catalyst. CRITICAL: Sportsbook odds movement is NOT a valid new catalyst — if your original thesis cited sportsbook lines and the proposed add-on also cites updated sportsbook odds, that is the same bet twice. Only factual real-world events qualify (injury, official announcement, standings change, political development). Sportsbook-only re-entry is prohibited even with a large price discount.
|
|
119
119
|
- exit_trigger is required on every trade. Be specific: "Exit when price hits 0.X" or "Exit when [specific news event]" — not "when narrative converges."
|
|
120
120
|
- Call get_budget_status AND get_positions at the start of each scan to know available capital and your current open positions. get_positions returns {"positions": [...], "closed_markets": [...]}. You MUST review BOTH before trading to apply concentration AND closed-market discipline correctly.`
|
|
121
121
|
}
|
package/dist/lib/paper-trade.js
CHANGED
|
@@ -28,7 +28,7 @@ function validatePlaceOrder(params, openPositions) {
|
|
|
28
28
|
params.price > 1) {
|
|
29
29
|
return `Error: price must be in range (0, 1]. Got: ${params.price}`;
|
|
30
30
|
}
|
|
31
|
-
const sameMarketPositions = openPositions.filter(p => p.market_id === params.market_id);
|
|
31
|
+
const sameMarketPositions = openPositions.filter(p => String(p.market_id) === String(params.market_id));
|
|
32
32
|
// Check 1: Existing position for same market requires new_catalyst
|
|
33
33
|
if (sameMarketPositions.length > 0 && !params.new_catalyst) {
|
|
34
34
|
return `Error: Position already exists for this market. Provide new_catalyst (specific new information from last 24h) to add.`;
|
package/dist/mcp-server.js
CHANGED
|
@@ -126,19 +126,21 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (req) => {
|
|
|
126
126
|
return false;
|
|
127
127
|
return !closedIds.has(`${p.market_id}_${p.outcome}_${p.ts}`);
|
|
128
128
|
});
|
|
129
|
+
// Normalize market_id to string to prevent type-mismatch bypasses
|
|
130
|
+
const marketId = String(a.market_id);
|
|
129
131
|
// Block re-entry into previously closed market+outcome combos
|
|
130
|
-
const marketOutcomePrefix = `${
|
|
132
|
+
const marketOutcomePrefix = `${marketId}_${a.outcome}_`;
|
|
131
133
|
const wasClosedBefore = Array.from(closedIds).some(id => id.startsWith(marketOutcomePrefix));
|
|
132
134
|
if (wasClosedBefore) {
|
|
133
|
-
return { content: [{ type: 'text', text: `Error: Re-entry blocked. This market+outcome (${
|
|
135
|
+
return { content: [{ type: 'text', text: `Error: Re-entry blocked. This market+outcome (${marketId} ${a.outcome}) was previously closed. Polly-gamba does not re-enter previously exited positions to prevent repeated losses on the same bet.` }] };
|
|
134
136
|
}
|
|
135
137
|
// Validate using extracted business logic (includes input validation + budget checks)
|
|
136
|
-
const validationError = (0, paper_trade_1.validatePlaceOrder)({ market_id:
|
|
138
|
+
const validationError = (0, paper_trade_1.validatePlaceOrder)({ market_id: marketId, outcome: a.outcome, size_usdc: a.size_usdc, price: a.price, new_catalyst: a.new_catalyst }, openPositions);
|
|
137
139
|
if (validationError) {
|
|
138
140
|
return { content: [{ type: 'text', text: validationError }] };
|
|
139
141
|
}
|
|
140
142
|
const position = {
|
|
141
|
-
market_id:
|
|
143
|
+
market_id: marketId,
|
|
142
144
|
market_question: a.market_question,
|
|
143
145
|
token_id: a.token_id,
|
|
144
146
|
outcome: a.outcome,
|
|
@@ -230,7 +232,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (req) => {
|
|
|
230
232
|
// Find matching open position — must check BOTH status field AND closedIds set
|
|
231
233
|
// (hard stops add to closedIds but cannot update the list entry's status field)
|
|
232
234
|
const match = positions.find((p) => {
|
|
233
|
-
if (p.market_id !== a.market_id)
|
|
235
|
+
if (String(p.market_id) !== String(a.market_id))
|
|
234
236
|
return false;
|
|
235
237
|
if (p.outcome?.toLowerCase() !== String(a.outcome).toLowerCase())
|
|
236
238
|
return false;
|
package/dist/position-monitor.js
CHANGED
|
@@ -71,20 +71,34 @@ class PositionMonitor {
|
|
|
71
71
|
}
|
|
72
72
|
// Build review candidates with current price data for Claude
|
|
73
73
|
const reviewCandidates = [];
|
|
74
|
-
// Track positions with no price data that have been
|
|
74
|
+
// Track positions with no price data that have been CONTINUOUSLY unavailable for >24h — likely resolved/delisted
|
|
75
|
+
// We use a Redis hash to record when price data first went missing per position key.
|
|
76
|
+
// A transient API outage should NOT trigger closure — only sustained unavailability counts.
|
|
75
77
|
const noPriceDataStale = [];
|
|
78
|
+
const noPriceSinceKey = `${this.prefix}:no_price_since`;
|
|
76
79
|
for (const pos of toCheck) {
|
|
77
80
|
const currentPrice = marketPriceCache.get(`${pos.market_id}|${pos.outcome}`) ?? null;
|
|
81
|
+
const posKey = `${pos.market_id}_${pos.outcome}_${pos.ts}`;
|
|
78
82
|
if (!currentPrice) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
83
|
+
// Record when we first noticed missing price data for this position
|
|
84
|
+
const existing = await this.redis.hget(noPriceSinceKey, posKey);
|
|
85
|
+
if (!existing) {
|
|
86
|
+
await this.redis.hset(noPriceSinceKey, posKey, String(Date.now()));
|
|
87
|
+
console.warn(`[position-monitor] WARNING: no price data for ${pos.market_id} ${pos.outcome} — first miss recorded, watching (market may be resolved or delisted)`);
|
|
82
88
|
}
|
|
83
89
|
else {
|
|
84
|
-
|
|
90
|
+
const hoursMissing = (Date.now() - parseInt(existing, 10)) / (1000 * 60 * 60);
|
|
91
|
+
if (hoursMissing >= 24) {
|
|
92
|
+
noPriceDataStale.push(pos);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
console.warn(`[position-monitor] WARNING: no price data for ${pos.market_id} ${pos.outcome} — missing ${hoursMissing.toFixed(1)}h (closes after 24h continuous)`);
|
|
96
|
+
}
|
|
85
97
|
}
|
|
86
98
|
continue;
|
|
87
99
|
}
|
|
100
|
+
// Price data available — clear any no-price-since tracker
|
|
101
|
+
await this.redis.hdel(noPriceSinceKey, posKey);
|
|
88
102
|
const entryPrice = pos.price;
|
|
89
103
|
const gain = (currentPrice.price - entryPrice) / entryPrice;
|
|
90
104
|
const hoursToEnd = (new Date(currentPrice.endDate).getTime() - Date.now()) / (1000 * 60 * 60);
|
|
@@ -115,11 +129,12 @@ class PositionMonitor {
|
|
|
115
129
|
continue;
|
|
116
130
|
const closed = { ...pos, status: 'closed', exit_price: pos.price, pnl: 0, closed_at: Date.now(), reason: 'market_unavailable' };
|
|
117
131
|
await this.redis.sadd(`${this.prefix}:closed_ids`, posKey);
|
|
132
|
+
await this.redis.hdel(noPriceSinceKey, posKey); // clean up tracker
|
|
118
133
|
await this.redis.lpush(`${this.prefix}:closed_positions`, JSON.stringify(closed));
|
|
119
134
|
await this.redis.ltrim(`${this.prefix}:closed_positions`, 0, 9999);
|
|
120
135
|
await this.redis.lpush(`${this.prefix}:log`, JSON.stringify({ type: 'position_closed', data: closed, ts: Date.now(), trigger: 'market_unavailable' }));
|
|
121
136
|
await this.redis.ltrim(`${this.prefix}:log`, 0, 9999);
|
|
122
|
-
console.log(`[position-monitor] CLOSED [market_unavailable] "${String(pos.market_question).slice(0, 50)}" ${pos.outcome} — no price data for >24h, freeing capital`);
|
|
137
|
+
console.log(`[position-monitor] CLOSED [market_unavailable] "${String(pos.market_question).slice(0, 50)}" ${pos.outcome} — no price data for >24h continuously, freeing capital`);
|
|
123
138
|
}
|
|
124
139
|
if (noPriceDataStale.length > 0) {
|
|
125
140
|
console.log(`[position-monitor] freed ${noPriceDataStale.length} stale no-price-data positions`);
|
package/dist/test/stress.js
CHANGED
|
@@ -376,6 +376,29 @@ async function runConcentrationTests() {
|
|
|
376
376
|
assert(err.includes('Budget cap'), `expected Budget cap error (not market cap), got: ${err}`);
|
|
377
377
|
});
|
|
378
378
|
}
|
|
379
|
+
async function runTypeCoercionTests() {
|
|
380
|
+
console.log('\n## I) Type Coercion — market_id string vs number');
|
|
381
|
+
await test('I1: numeric market_id in params matches string market_id in position', async () => {
|
|
382
|
+
// Simulates Claude passing market_id as a number (e.g., 564166) while
|
|
383
|
+
// Redis stores it as a string ("564166"). Without String() coercion,
|
|
384
|
+
// sameMarketPositions would be empty → 20% discount check bypassed.
|
|
385
|
+
const openPositions = [
|
|
386
|
+
makePosition({ market_id: '564166', outcome: 'YES', price: 0.30, ts: 1 })
|
|
387
|
+
];
|
|
388
|
+
const err = (0, paper_trade_1.validatePlaceOrder)({ market_id: 564166, outcome: 'YES', size_usdc: 10, price: 0.29, new_catalyst: 'New result' }, openPositions);
|
|
389
|
+
// 0.29 > 0.30 * 0.80 = 0.24 → should be blocked (not a 20% discount)
|
|
390
|
+
assert(err !== null, 'expected re-entry blocked: numeric market_id must match string in position');
|
|
391
|
+
assert(err.includes('Re-entry blocked'), `expected Re-entry blocked error, got: ${err}`);
|
|
392
|
+
});
|
|
393
|
+
await test('I2: numeric market_id with sufficient discount is allowed', async () => {
|
|
394
|
+
const openPositions = [
|
|
395
|
+
makePosition({ market_id: '564166', outcome: 'YES', price: 0.30, ts: 1 })
|
|
396
|
+
];
|
|
397
|
+
const err = (0, paper_trade_1.validatePlaceOrder)({ market_id: 564166, outcome: 'YES', size_usdc: 10, price: 0.23, new_catalyst: 'Sportsbook update' }, openPositions);
|
|
398
|
+
// 0.23 <= 0.30 * 0.80 = 0.24 → allowed (>20% discount)
|
|
399
|
+
assert(err === null, `expected success with 20%+ discount even with numeric market_id, got: ${err}`);
|
|
400
|
+
});
|
|
401
|
+
}
|
|
379
402
|
// ─── Main ─────────────────────────────────────────────────────────────────────
|
|
380
403
|
async function main() {
|
|
381
404
|
console.log('\n[stress] polly-gamba paper trading system — stress tests');
|
|
@@ -389,6 +412,7 @@ async function main() {
|
|
|
389
412
|
await runHardStopTests();
|
|
390
413
|
await runDoubleCloseBugTests();
|
|
391
414
|
await runConcentrationTests();
|
|
415
|
+
await runTypeCoercionTests();
|
|
392
416
|
console.log(`\n[stress] ─── Results ─── ${passed} passed, ${failed} failed\n`);
|
|
393
417
|
if (bugReport.length > 0) {
|
|
394
418
|
console.log('[stress] Bug findings:');
|
package/package.json
CHANGED
package/service.log
CHANGED
|
@@ -2469,3 +2469,337 @@ npm warn deprecated prebuild-install@7.1.3: No longer maintained. Please contact
|
|
|
2469
2469
|
[position-monitor] WARNING: no price data for 562828 NO — skipping review (market may be resolved or delisted)
|
|
2470
2470
|
[position-monitor] WARNING: no price data for 559651 NO — skipping review (market may be resolved or delisted)
|
|
2471
2471
|
[position-monitor] checked=24 review_candidates=3 hard_stops=0 (moved>5% or <72h expiry)
|
|
2472
|
+
[polly-gamba] Starting paper trading service
|
|
2473
|
+
[polly-gamba] Claude cwd: /Users/feral/polly-gamba
|
|
2474
|
+
[polly-gamba] Expiring trader cwd: /Users/feral/polly-gamba-expiring
|
|
2475
|
+
[coinbase-ws] Connecting to wss://ws-feed.exchange.coinbase.com
|
|
2476
|
+
[polly-gamba] Listening for BTC/ETH price signals (threshold: 0.5% in 60s)...
|
|
2477
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2478
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2479
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2480
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2481
|
+
[coinbase-ws] Connected
|
|
2482
|
+
[gamma] Loaded 494 markets (filtered from 500)
|
|
2483
|
+
[scan] 20 high-quality markets for autonomous review
|
|
2484
|
+
[gamma] Loaded 494 markets (filtered from 500)
|
|
2485
|
+
[expiring] 0 expiring markets for review
|
|
2486
|
+
[expiring] no expiring markets found this cycle
|
|
2487
|
+
[position-monitor] checked=24 review_candidates=5 hard_stops=0 (moved>5% or <72h expiry)
|
|
2488
|
+
[claude-trader:anthropic] ready
|
|
2489
|
+
[claude-trader:ollama] ready
|
|
2490
|
+
[claude-trader:expiring] ready
|
|
2491
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2492
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2493
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2494
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2495
|
+
[expiring] failed to fetch markets: fetch failed
|
|
2496
|
+
[gamma] Loaded 494 markets (filtered from 500)
|
|
2497
|
+
[scan] 20 high-quality markets for autonomous review
|
|
2498
|
+
[position-monitor] WARNING: no price data for 553830 NO — skipping review (market may be resolved or delisted)
|
|
2499
|
+
[position-monitor] CLOSED [market_unavailable] "Will Spain win the 2026 FIFA World Cup?" YES — no price data for >24h, freeing capital
|
|
2500
|
+
[position-monitor] CLOSED [market_unavailable] "Will Arsenal win the 2025-26 Champions League?" NO — no price data for >24h, freeing capital
|
|
2501
|
+
[position-monitor] CLOSED [market_unavailable] "Will Jesus Christ return before GTA VI?" NO — no price data for >24h, freeing capital
|
|
2502
|
+
[position-monitor] CLOSED [market_unavailable] "Will Scottie Scheffler win the 2026 Masters tourna" YES — no price data for >24h, freeing capital
|
|
2503
|
+
[position-monitor] CLOSED [market_unavailable] "Will France win the 2026 FIFA World Cup?" YES — no price data for >24h, freeing capital
|
|
2504
|
+
[position-monitor] CLOSED [market_unavailable] "Will the San Antonio Spurs win the 2026 NBA Finals" NO — no price data for >24h, freeing capital
|
|
2505
|
+
[position-monitor] freed 6 stale no-price-data positions
|
|
2506
|
+
[position-monitor] checked=24 review_candidates=3 hard_stops=0 (moved>5% or <72h expiry)
|
|
2507
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2508
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2509
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2510
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2511
|
+
[scan] failed to fetch markets: fetch failed
|
|
2512
|
+
[expiring] failed to fetch markets: fetch failed
|
|
2513
|
+
[position-monitor] WARNING: no price data for 553830 NO — skipping review (market may be resolved or delisted)
|
|
2514
|
+
[position-monitor] CLOSED [market_unavailable] "Will Gavin Newsom win the 2028 Democratic presiden" NO — no price data for >24h, freeing capital
|
|
2515
|
+
[position-monitor] CLOSED [market_unavailable] "Zelenskyy out as Ukraine president by end of 2026?" NO — no price data for >24h, freeing capital
|
|
2516
|
+
[position-monitor] CLOSED [market_unavailable] "Will Bayern Munich win the 2025–26 Champions Leagu" NO — no price data for >24h, freeing capital
|
|
2517
|
+
[position-monitor] CLOSED [market_unavailable] "Will bitcoin hit $1m before GTA VI?" NO — no price data for >24h, freeing capital
|
|
2518
|
+
[position-monitor] CLOSED [market_unavailable] "Xi Jinping out before 2027?" NO — no price data for >24h, freeing capital
|
|
2519
|
+
[position-monitor] CLOSED [market_unavailable] "Will China invade Taiwan by end of 2026?" NO — no price data for >24h, freeing capital
|
|
2520
|
+
[position-monitor] freed 6 stale no-price-data positions
|
|
2521
|
+
[position-monitor] checked=18 review_candidates=3 hard_stops=0 (moved>5% or <72h expiry)
|
|
2522
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2523
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2524
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2525
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2526
|
+
[scan] failed to fetch markets: fetch failed
|
|
2527
|
+
[position-monitor] WARNING: no price data for 553830 NO — skipping review (market may be resolved or delisted)
|
|
2528
|
+
[position-monitor] CLOSED [market_unavailable] "Will the Boston Celtics win the 2026 NBA Finals?" YES — no price data for >24h, freeing capital
|
|
2529
|
+
[position-monitor] CLOSED [market_unavailable] "2026 Balance of Power: D Senate, D House" NO — no price data for >24h, freeing capital
|
|
2530
|
+
[position-monitor] CLOSED [market_unavailable] "Will Manchester City win the 2025–26 English Premi" NO — no price data for >24h, freeing capital
|
|
2531
|
+
[position-monitor] CLOSED [market_unavailable] "Putin out as President of Russia by December 31, 2" NO — no price data for >24h, freeing capital
|
|
2532
|
+
[position-monitor] CLOSED [market_unavailable] "Will Gavin Newsom win the 2028 US Presidential Ele" NO — no price data for >24h, freeing capital
|
|
2533
|
+
[position-monitor] CLOSED [market_unavailable] "Will Marco Rubio win the 2028 Republican president" NO — no price data for >24h, freeing capital
|
|
2534
|
+
[position-monitor] CLOSED [market_unavailable] "Will J.D. Vance win the 2028 Republican presidenti" YES — no price data for >24h, freeing capital
|
|
2535
|
+
[position-monitor] CLOSED [market_unavailable] "Will the next Prime Minister of Hungary be Péter M" NO — no price data for >24h, freeing capital
|
|
2536
|
+
[position-monitor] CLOSED [market_unavailable] "Will the next Prime Minister of Hungary be Viktor " YES — no price data for >24h, freeing capital
|
|
2537
|
+
[position-monitor] CLOSED [market_unavailable] "Russia x Ukraine ceasefire by end of 2026?" NO — no price data for >24h, freeing capital
|
|
2538
|
+
[position-monitor] CLOSED [market_unavailable] "Will John Cornyn win the 2026 Texas Republican Pri" YES — no price data for >24h, freeing capital
|
|
2539
|
+
[position-monitor] freed 11 stale no-price-data positions
|
|
2540
|
+
[position-monitor] checked=12 review_candidates=0 hard_stops=0 (moved>5% or <72h expiry)
|
|
2541
|
+
[gamma] Loaded 494 markets (filtered from 500)
|
|
2542
|
+
[expiring] 0 expiring markets for review
|
|
2543
|
+
[expiring] no expiring markets found this cycle
|
|
2544
|
+
[signal] ETH up 0.50% @ $2,146.9 over 55s
|
|
2545
|
+
[signal] ETH up 0.50% @ $2,146.9
|
|
2546
|
+
[match] 20 markets for ETH signal
|
|
2547
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2548
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2549
|
+
[scan] failed to fetch markets: fetch failed
|
|
2550
|
+
[position-monitor] WARNING: no price data for 553830 NO — skipping review (market may be resolved or delisted)
|
|
2551
|
+
[position-monitor] checked=1 review_candidates=0 hard_stops=0 (moved>5% or <72h expiry)
|
|
2552
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2553
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2554
|
+
[gamma] Loaded 494 markets (filtered from 500)
|
|
2555
|
+
[expiring] 0 expiring markets for review
|
|
2556
|
+
[expiring] no expiring markets found this cycle
|
|
2557
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2558
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2559
|
+
[position-monitor] WARNING: no price data for 553830 NO — skipping review (market may be resolved or delisted)
|
|
2560
|
+
[position-monitor] checked=1 review_candidates=0 hard_stops=0 (moved>5% or <72h expiry)
|
|
2561
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2562
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2563
|
+
[scan] failed to fetch markets: fetch failed
|
|
2564
|
+
[expiring] failed to fetch markets: fetch failed
|
|
2565
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2566
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2567
|
+
[position-monitor] WARNING: no price data for 553830 NO — skipping review (market may be resolved or delisted)
|
|
2568
|
+
[position-monitor] checked=1 review_candidates=0 hard_stops=0 (moved>5% or <72h expiry)
|
|
2569
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2570
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2571
|
+
[expiring] failed to fetch markets: fetch failed
|
|
2572
|
+
[gamma] Loaded 494 markets (filtered from 500)
|
|
2573
|
+
[scan] 18 high-quality markets for autonomous review
|
|
2574
|
+
[signal] BTC up 0.50% @ $70,106.04 over 14s
|
|
2575
|
+
[signal] BTC up 0.50% @ $70,106.04
|
|
2576
|
+
[match] 1 markets for BTC signal
|
|
2577
|
+
[signal] ETH up 0.50% @ $2,164.32 over 9s
|
|
2578
|
+
[signal] ETH up 0.50% @ $2,164.32
|
|
2579
|
+
[match] 20 markets for ETH signal
|
|
2580
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2581
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2582
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2583
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2584
|
+
[scan] failed to fetch markets: fetch failed
|
|
2585
|
+
[position-monitor] WARNING: no price data for 553830 NO — skipping review (market may be resolved or delisted)
|
|
2586
|
+
[position-monitor] checked=1 review_candidates=0 hard_stops=0 (moved>5% or <72h expiry)
|
|
2587
|
+
[expiring] failed to fetch markets: fetch failed
|
|
2588
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2589
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2590
|
+
[position-monitor] WARNING: no price data for 553830 NO — skipping review (market may be resolved or delisted)
|
|
2591
|
+
[position-monitor] checked=1 review_candidates=0 hard_stops=0 (moved>5% or <72h expiry)
|
|
2592
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2593
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2594
|
+
[scan] failed to fetch markets: fetch failed
|
|
2595
|
+
[gamma] Loaded 494 markets (filtered from 500)
|
|
2596
|
+
[expiring] 0 expiring markets for review
|
|
2597
|
+
[expiring] no expiring markets found this cycle
|
|
2598
|
+
[position-monitor] checked=1 review_candidates=0 hard_stops=0 (moved>5% or <72h expiry)
|
|
2599
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2600
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2601
|
+
[scan] failed to fetch markets: fetch failed
|
|
2602
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2603
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2604
|
+
[expiring] failed to fetch markets: fetch failed
|
|
2605
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2606
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2607
|
+
[position-monitor] WARNING: no price data for 553830 NO — skipping review (market may be resolved or delisted)
|
|
2608
|
+
[position-monitor] checked=1 review_candidates=0 hard_stops=0 (moved>5% or <72h expiry)
|
|
2609
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2610
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2611
|
+
[expiring] failed to fetch markets: fetch failed
|
|
2612
|
+
[gamma] Loaded 494 markets (filtered from 500)
|
|
2613
|
+
[scan] 18 high-quality markets for autonomous review
|
|
2614
|
+
[position-monitor] checked=1 review_candidates=0 hard_stops=0 (moved>5% or <72h expiry)
|
|
2615
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2616
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2617
|
+
[scan] failed to fetch markets: fetch failed
|
|
2618
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2619
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2620
|
+
[gamma] Loaded 495 markets (filtered from 500)
|
|
2621
|
+
[expiring] 0 expiring markets for review
|
|
2622
|
+
[expiring] no expiring markets found this cycle
|
|
2623
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2624
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2625
|
+
[position-monitor] WARNING: no price data for 553830 NO — skipping review (market may be resolved or delisted)
|
|
2626
|
+
[position-monitor] checked=1 review_candidates=0 hard_stops=0 (moved>5% or <72h expiry)
|
|
2627
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2628
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2629
|
+
[expiring] failed to fetch markets: fetch failed
|
|
2630
|
+
[gamma] Loaded 495 markets (filtered from 500)
|
|
2631
|
+
[scan] 19 high-quality markets for autonomous review
|
|
2632
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2633
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2634
|
+
[position-monitor] WARNING: no price data for 553830 NO — skipping review (market may be resolved or delisted)
|
|
2635
|
+
[position-monitor] checked=1 review_candidates=0 hard_stops=0 (moved>5% or <72h expiry)
|
|
2636
|
+
[scan] failed to fetch markets: fetch failed
|
|
2637
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2638
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2639
|
+
[gamma] Loaded 495 markets (filtered from 500)
|
|
2640
|
+
[expiring] 0 expiring markets for review
|
|
2641
|
+
[expiring] no expiring markets found this cycle
|
|
2642
|
+
[position-monitor] WARNING: no price data for 553830 NO — skipping review (market may be resolved or delisted)
|
|
2643
|
+
[position-monitor] checked=1 review_candidates=0 hard_stops=0 (moved>5% or <72h expiry)
|
|
2644
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2645
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2646
|
+
[gamma] Loaded 495 markets (filtered from 500)
|
|
2647
|
+
[scan] 21 high-quality markets for autonomous review
|
|
2648
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2649
|
+
[expiring] 0 expiring markets for review
|
|
2650
|
+
[expiring] no expiring markets found this cycle
|
|
2651
|
+
[position-monitor] WARNING: no price data for 553830 NO — skipping review (market may be resolved or delisted)
|
|
2652
|
+
[position-monitor] checked=1 review_candidates=0 hard_stops=0 (moved>5% or <72h expiry)
|
|
2653
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2654
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2655
|
+
[scan] failed to fetch markets: fetch failed
|
|
2656
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2657
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2658
|
+
[gamma] Loaded 495 markets (filtered from 500)
|
|
2659
|
+
[expiring] 0 expiring markets for review
|
|
2660
|
+
[expiring] no expiring markets found this cycle
|
|
2661
|
+
[position-monitor] WARNING: no price data for 553830 NO — skipping review (market may be resolved or delisted)
|
|
2662
|
+
[position-monitor] checked=1 review_candidates=0 hard_stops=0 (moved>5% or <72h expiry)
|
|
2663
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2664
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2665
|
+
[scan] failed to fetch markets: fetch failed
|
|
2666
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2667
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2668
|
+
[gamma] Loaded 495 markets (filtered from 500)
|
|
2669
|
+
[expiring] 0 expiring markets for review
|
|
2670
|
+
[expiring] no expiring markets found this cycle
|
|
2671
|
+
[position-monitor] checked=1 review_candidates=0 hard_stops=0 (moved>5% or <72h expiry)
|
|
2672
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2673
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2674
|
+
[scan] failed to fetch markets: fetch failed
|
|
2675
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2676
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2677
|
+
[expiring] failed to fetch markets: fetch failed
|
|
2678
|
+
[position-monitor] WARNING: no price data for 553830 NO — skipping review (market may be resolved or delisted)
|
|
2679
|
+
[position-monitor] checked=1 review_candidates=0 hard_stops=0 (moved>5% or <72h expiry)
|
|
2680
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2681
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2682
|
+
[gamma] Loaded 495 markets (filtered from 500)
|
|
2683
|
+
[scan] 20 high-quality markets for autonomous review
|
|
2684
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2685
|
+
[expiring] 0 expiring markets for review
|
|
2686
|
+
[expiring] no expiring markets found this cycle
|
|
2687
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2688
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2689
|
+
[position-monitor] WARNING: no price data for 553830 NO — skipping review (market may be resolved or delisted)
|
|
2690
|
+
[position-monitor] checked=1 review_candidates=0 hard_stops=0 (moved>5% or <72h expiry)
|
|
2691
|
+
[gamma] Loaded 495 markets (filtered from 500)
|
|
2692
|
+
[scan] 20 high-quality markets for autonomous review
|
|
2693
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2694
|
+
[expiring] 0 expiring markets for review
|
|
2695
|
+
[expiring] no expiring markets found this cycle
|
|
2696
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2697
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2698
|
+
[position-monitor] WARNING: no price data for 553830 NO — skipping review (market may be resolved or delisted)
|
|
2699
|
+
[position-monitor] checked=1 review_candidates=0 hard_stops=0 (moved>5% or <72h expiry)
|
|
2700
|
+
[gamma] Loaded 495 markets (filtered from 500)
|
|
2701
|
+
[scan] 18 high-quality markets for autonomous review
|
|
2702
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2703
|
+
[expiring] 0 expiring markets for review
|
|
2704
|
+
[expiring] no expiring markets found this cycle
|
|
2705
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2706
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2707
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2708
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2709
|
+
[position-monitor] WARNING: no price data for 553830 NO — skipping review (market may be resolved or delisted)
|
|
2710
|
+
[position-monitor] CLOSED [market_unavailable] "Will Spain win the 2026 FIFA World Cup?" YES — no price data for >24h, freeing capital
|
|
2711
|
+
[position-monitor] CLOSED [market_unavailable] "Will Arsenal win the 2025-26 Champions League?" NO — no price data for >24h, freeing capital
|
|
2712
|
+
[position-monitor] CLOSED [market_unavailable] "Will Jesus Christ return before GTA VI?" NO — no price data for >24h, freeing capital
|
|
2713
|
+
[position-monitor] CLOSED [market_unavailable] "Will Scottie Scheffler win the 2026 Masters tourna" YES — no price data for >24h, freeing capital
|
|
2714
|
+
[position-monitor] CLOSED [market_unavailable] "Will the San Antonio Spurs win the 2026 NBA Finals" NO — no price data for >24h, freeing capital
|
|
2715
|
+
[position-monitor] CLOSED [market_unavailable] "Xi Jinping out before 2027?" NO — no price data for >24h, freeing capital
|
|
2716
|
+
[position-monitor] CLOSED [market_unavailable] "Will China invade Taiwan by end of 2026?" NO — no price data for >24h, freeing capital
|
|
2717
|
+
[position-monitor] CLOSED [market_unavailable] "Putin out as President of Russia by December 31, 2" NO — no price data for >24h, freeing capital
|
|
2718
|
+
[position-monitor] CLOSED [market_unavailable] "Will Gavin Newsom win the 2028 US Presidential Ele" NO — no price data for >24h, freeing capital
|
|
2719
|
+
[position-monitor] CLOSED [market_unavailable] "Will Marco Rubio win the 2028 Republican president" NO — no price data for >24h, freeing capital
|
|
2720
|
+
[position-monitor] CLOSED [market_unavailable] "Will J.D. Vance win the 2028 Republican presidenti" YES — no price data for >24h, freeing capital
|
|
2721
|
+
[position-monitor] CLOSED [market_unavailable] "Will the next Prime Minister of Hungary be Péter M" NO — no price data for >24h, freeing capital
|
|
2722
|
+
[position-monitor] CLOSED [market_unavailable] "Will the next Prime Minister of Hungary be Viktor " YES — no price data for >24h, freeing capital
|
|
2723
|
+
[position-monitor] CLOSED [market_unavailable] "Russia x Ukraine ceasefire by end of 2026?" NO — no price data for >24h, freeing capital
|
|
2724
|
+
[position-monitor] CLOSED [market_unavailable] "Will John Cornyn win the 2026 Texas Republican Pri" YES — no price data for >24h, freeing capital
|
|
2725
|
+
[position-monitor] freed 15 stale no-price-data positions
|
|
2726
|
+
[position-monitor] checked=24 review_candidates=2 hard_stops=0 (moved>5% or <72h expiry)
|
|
2727
|
+
[gamma] Loaded 494 markets (filtered from 500)
|
|
2728
|
+
[scan] 18 high-quality markets for autonomous review
|
|
2729
|
+
[gamma] Loaded 495 markets (filtered from 500)
|
|
2730
|
+
[expiring] 0 expiring markets for review
|
|
2731
|
+
[expiring] no expiring markets found this cycle
|
|
2732
|
+
[position-monitor] checked=9 review_candidates=2 hard_stops=0 (moved>5% or <72h expiry)
|
|
2733
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2734
|
+
[scan] 18 high-quality markets for autonomous review
|
|
2735
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2736
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2737
|
+
[expiring] failed to fetch markets: fetch failed
|
|
2738
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2739
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2740
|
+
[scan] failed to fetch markets: fetch failed
|
|
2741
|
+
[position-monitor] WARNING: no price data for 553830 NO — skipping review (market may be resolved or delisted)
|
|
2742
|
+
[position-monitor] CLOSED [market_unavailable] "Will Gavin Newsom win the 2028 Democratic presiden" NO — no price data for >24h, freeing capital
|
|
2743
|
+
[position-monitor] CLOSED [market_unavailable] "Will France win the 2026 FIFA World Cup?" YES — no price data for >24h, freeing capital
|
|
2744
|
+
[position-monitor] CLOSED [market_unavailable] "Zelenskyy out as Ukraine president by end of 2026?" NO — no price data for >24h, freeing capital
|
|
2745
|
+
[position-monitor] CLOSED [market_unavailable] "Will bitcoin hit $1m before GTA VI?" NO — no price data for >24h, freeing capital
|
|
2746
|
+
[position-monitor] CLOSED [market_unavailable] "2026 Balance of Power: D Senate, D House" NO — no price data for >24h, freeing capital
|
|
2747
|
+
[position-monitor] CLOSED [market_unavailable] "Will Manchester City win the 2025–26 English Premi" NO — no price data for >24h, freeing capital
|
|
2748
|
+
[position-monitor] freed 6 stale no-price-data positions
|
|
2749
|
+
[position-monitor] checked=9 review_candidates=1 hard_stops=0 (moved>5% or <72h expiry)
|
|
2750
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2751
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2752
|
+
[expiring] failed to fetch markets: fetch failed
|
|
2753
|
+
[position-monitor] WARNING: no price data for 553830 NO — skipping review (market may be resolved or delisted)
|
|
2754
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2755
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2756
|
+
[position-monitor] CLOSED [market_unavailable] "Will Bayern Munich win the 2025–26 Champions Leagu" NO — no price data for >24h, freeing capital
|
|
2757
|
+
[position-monitor] CLOSED [market_unavailable] "Will the Boston Celtics win the 2026 NBA Finals?" YES — no price data for >24h, freeing capital
|
|
2758
|
+
[position-monitor] freed 2 stale no-price-data positions
|
|
2759
|
+
[position-monitor] checked=3 review_candidates=0 hard_stops=0 (moved>5% or <72h expiry)
|
|
2760
|
+
[gamma] Loaded 494 markets (filtered from 500)
|
|
2761
|
+
[scan] 16 high-quality markets for autonomous review
|
|
2762
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2763
|
+
[expiring] 0 expiring markets for review
|
|
2764
|
+
[expiring] no expiring markets found this cycle
|
|
2765
|
+
[signal] ETH up 0.50% @ $2,155.82 over 60s
|
|
2766
|
+
[signal] ETH up 0.50% @ $2,155.82
|
|
2767
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2768
|
+
[gamma] Loaded 484 markets (filtered from 500)
|
|
2769
|
+
[match] 20 markets for ETH signal
|
|
2770
|
+
[position-monitor] WARNING: no price data for 553830 NO — skipping review (market may be resolved or delisted)
|
|
2771
|
+
[position-monitor] checked=1 review_candidates=0 hard_stops=0 (moved>5% or <72h expiry)
|
|
2772
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2773
|
+
[scan] 16 high-quality markets for autonomous review
|
|
2774
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2775
|
+
[expiring] 0 expiring markets for review
|
|
2776
|
+
[expiring] no expiring markets found this cycle
|
|
2777
|
+
[position-monitor] checked=1 review_candidates=0 hard_stops=0 (moved>5% or <72h expiry)
|
|
2778
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2779
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2780
|
+
[scan] failed to fetch markets: fetch failed
|
|
2781
|
+
[signal] ETH up 0.50% @ $2,156.26 over 39s
|
|
2782
|
+
[signal] ETH up 0.50% @ $2,156.26
|
|
2783
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2784
|
+
[gamma] Loaded 484 markets (filtered from 500)
|
|
2785
|
+
[match] 20 markets for ETH signal
|
|
2786
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2787
|
+
[expiring] 0 expiring markets for review
|
|
2788
|
+
[expiring] no expiring markets found this cycle
|
|
2789
|
+
[position-monitor] checked=1 review_candidates=0 hard_stops=0 (moved>5% or <72h expiry)
|
|
2790
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2791
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2792
|
+
[scan] failed to fetch markets: fetch failed
|
|
2793
|
+
[signal] ETH down -0.50% @ $2,148 over 60s
|
|
2794
|
+
[signal] ETH down 0.50% @ $2,148
|
|
2795
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2796
|
+
[expiring] fetching expiring markets (closing within 72h, vol24h>$10k, liq>$10k, price 0.05-0.95)
|
|
2797
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2798
|
+
[expiring] failed to fetch markets: fetch failed
|
|
2799
|
+
[error] failed to fetch markets: fetch failed
|
|
2800
|
+
[position-monitor] WARNING: no price data for 553830 NO — skipping review (market may be resolved or delisted)
|
|
2801
|
+
[position-monitor] checked=1 review_candidates=0 hard_stops=0 (moved>5% or <72h expiry)
|
|
2802
|
+
[scan] fetching high-quality markets (vol24h>$50k, liq>$50k, price 0.10-0.90)
|
|
2803
|
+
[gamma] Fetching active markets from https://gamma-api.polymarket.com/markets?active=true&closed=false&limit=500
|
|
2804
|
+
[gamma] Loaded 493 markets (filtered from 500)
|
|
2805
|
+
[scan] 16 high-quality markets for autonomous review
|
package/src/position-monitor.ts
CHANGED
|
@@ -106,20 +106,34 @@ export class PositionMonitor {
|
|
|
106
106
|
reasoning?: string
|
|
107
107
|
}> = []
|
|
108
108
|
|
|
109
|
-
// Track positions with no price data that have been
|
|
109
|
+
// Track positions with no price data that have been CONTINUOUSLY unavailable for >24h — likely resolved/delisted
|
|
110
|
+
// We use a Redis hash to record when price data first went missing per position key.
|
|
111
|
+
// A transient API outage should NOT trigger closure — only sustained unavailability counts.
|
|
110
112
|
const noPriceDataStale: Position[] = []
|
|
113
|
+
const noPriceSinceKey = `${this.prefix}:no_price_since`
|
|
111
114
|
for (const pos of toCheck) {
|
|
112
115
|
const currentPrice = marketPriceCache.get(`${pos.market_id}|${pos.outcome}`) ?? null
|
|
116
|
+
const posKey = `${pos.market_id}_${pos.outcome}_${pos.ts}`
|
|
113
117
|
if (!currentPrice) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
118
|
+
// Record when we first noticed missing price data for this position
|
|
119
|
+
const existing = await this.redis.hget(noPriceSinceKey, posKey)
|
|
120
|
+
if (!existing) {
|
|
121
|
+
await this.redis.hset(noPriceSinceKey, posKey, String(Date.now()))
|
|
122
|
+
console.warn(`[position-monitor] WARNING: no price data for ${pos.market_id} ${pos.outcome} — first miss recorded, watching (market may be resolved or delisted)`)
|
|
117
123
|
} else {
|
|
118
|
-
|
|
124
|
+
const hoursMissing = (Date.now() - parseInt(existing, 10)) / (1000 * 60 * 60)
|
|
125
|
+
if (hoursMissing >= 24) {
|
|
126
|
+
noPriceDataStale.push(pos)
|
|
127
|
+
} else {
|
|
128
|
+
console.warn(`[position-monitor] WARNING: no price data for ${pos.market_id} ${pos.outcome} — missing ${hoursMissing.toFixed(1)}h (closes after 24h continuous)`)
|
|
129
|
+
}
|
|
119
130
|
}
|
|
120
131
|
continue
|
|
121
132
|
}
|
|
122
133
|
|
|
134
|
+
// Price data available — clear any no-price-since tracker
|
|
135
|
+
await this.redis.hdel(noPriceSinceKey, posKey)
|
|
136
|
+
|
|
123
137
|
const entryPrice = pos.price
|
|
124
138
|
const gain = (currentPrice.price - entryPrice) / entryPrice
|
|
125
139
|
const hoursToEnd = (new Date(currentPrice.endDate).getTime() - Date.now()) / (1000 * 60 * 60)
|
|
@@ -153,11 +167,12 @@ export class PositionMonitor {
|
|
|
153
167
|
|
|
154
168
|
const closed = { ...pos, status: 'closed', exit_price: pos.price, pnl: 0, closed_at: Date.now(), reason: 'market_unavailable' }
|
|
155
169
|
await this.redis.sadd(`${this.prefix}:closed_ids`, posKey)
|
|
170
|
+
await this.redis.hdel(noPriceSinceKey, posKey) // clean up tracker
|
|
156
171
|
await this.redis.lpush(`${this.prefix}:closed_positions`, JSON.stringify(closed))
|
|
157
172
|
await this.redis.ltrim(`${this.prefix}:closed_positions`, 0, 9999)
|
|
158
173
|
await this.redis.lpush(`${this.prefix}:log`, JSON.stringify({ type: 'position_closed', data: closed, ts: Date.now(), trigger: 'market_unavailable' }))
|
|
159
174
|
await this.redis.ltrim(`${this.prefix}:log`, 0, 9999)
|
|
160
|
-
console.log(`[position-monitor] CLOSED [market_unavailable] "${String(pos.market_question).slice(0, 50)}" ${pos.outcome} — no price data for >24h, freeing capital`)
|
|
175
|
+
console.log(`[position-monitor] CLOSED [market_unavailable] "${String(pos.market_question).slice(0, 50)}" ${pos.outcome} — no price data for >24h continuously, freeing capital`)
|
|
161
176
|
}
|
|
162
177
|
if (noPriceDataStale.length > 0) {
|
|
163
178
|
console.log(`[position-monitor] freed ${noPriceDataStale.length} stale no-price-data positions`)
|
package/src/test/stress.ts
CHANGED
|
@@ -508,6 +508,38 @@ async function runConcentrationTests(): Promise<void> {
|
|
|
508
508
|
})
|
|
509
509
|
}
|
|
510
510
|
|
|
511
|
+
async function runTypeCoercionTests(): Promise<void> {
|
|
512
|
+
console.log('\n## I) Type Coercion — market_id string vs number')
|
|
513
|
+
|
|
514
|
+
await test('I1: numeric market_id in params matches string market_id in position', async () => {
|
|
515
|
+
// Simulates Claude passing market_id as a number (e.g., 564166) while
|
|
516
|
+
// Redis stores it as a string ("564166"). Without String() coercion,
|
|
517
|
+
// sameMarketPositions would be empty → 20% discount check bypassed.
|
|
518
|
+
const openPositions = [
|
|
519
|
+
makePosition({ market_id: '564166', outcome: 'YES', price: 0.30, ts: 1 })
|
|
520
|
+
]
|
|
521
|
+
const err = validatePlaceOrder(
|
|
522
|
+
{ market_id: 564166 as any, outcome: 'YES', size_usdc: 10, price: 0.29, new_catalyst: 'New result' },
|
|
523
|
+
openPositions
|
|
524
|
+
)
|
|
525
|
+
// 0.29 > 0.30 * 0.80 = 0.24 → should be blocked (not a 20% discount)
|
|
526
|
+
assert(err !== null, 'expected re-entry blocked: numeric market_id must match string in position')
|
|
527
|
+
assert(err!.includes('Re-entry blocked'), `expected Re-entry blocked error, got: ${err}`)
|
|
528
|
+
})
|
|
529
|
+
|
|
530
|
+
await test('I2: numeric market_id with sufficient discount is allowed', async () => {
|
|
531
|
+
const openPositions = [
|
|
532
|
+
makePosition({ market_id: '564166', outcome: 'YES', price: 0.30, ts: 1 })
|
|
533
|
+
]
|
|
534
|
+
const err = validatePlaceOrder(
|
|
535
|
+
{ market_id: 564166 as any, outcome: 'YES', size_usdc: 10, price: 0.23, new_catalyst: 'Sportsbook update' },
|
|
536
|
+
openPositions
|
|
537
|
+
)
|
|
538
|
+
// 0.23 <= 0.30 * 0.80 = 0.24 → allowed (>20% discount)
|
|
539
|
+
assert(err === null, `expected success with 20%+ discount even with numeric market_id, got: ${err}`)
|
|
540
|
+
})
|
|
541
|
+
}
|
|
542
|
+
|
|
511
543
|
// ─── Main ─────────────────────────────────────────────────────────────────────
|
|
512
544
|
|
|
513
545
|
async function main(): Promise<void> {
|
|
@@ -523,6 +555,7 @@ async function main(): Promise<void> {
|
|
|
523
555
|
await runHardStopTests()
|
|
524
556
|
await runDoubleCloseBugTests()
|
|
525
557
|
await runConcentrationTests()
|
|
558
|
+
await runTypeCoercionTests()
|
|
526
559
|
|
|
527
560
|
console.log(`\n[stress] ─── Results ─── ${passed} passed, ${failed} failed\n`)
|
|
528
561
|
|