diff --git a/package.json b/package.json index 70bec20..81eebb8 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,8 @@ "type": "module", "private": true, "scripts": { - "start": "node src/index.js", - "watch:telegram": "node scripts/telegram-watcher.js" + "start": "node --env-file=env src/index.js", + "watch:telegram": "node --env-file=env scripts/telegram-watcher.js" }, "dependencies": { "ethers": "^6.11.1", diff --git a/scripts/telegram-watcher.js b/scripts/telegram-watcher.js index e96b796..470b263 100644 --- a/scripts/telegram-watcher.js +++ b/scripts/telegram-watcher.js @@ -10,12 +10,14 @@ try { applyGlobalProxyFromEnv(); } catch {} +const { CONFIG } = await import(path.join(ROOT, "src/config.js")); + const BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN; const CHAT_ID = process.env.TELEGRAM_CHAT_ID; const CSV_PATH = process.env.SIGNALS_CSV || path.join(ROOT, "logs/signals.csv"); -const COOLDOWN_MS = Number(process.env.TELEGRAM_COOLDOWN_MS) || 30_000; const DRY_RUN = process.env.DRY_RUN === "true"; const POLY_BASE = process.env.POLYMARKET_BASE_URL || "https://polymarket.com/zh/event"; +const WINDOW_MS = CONFIG.candleWindowMinutes * 60_000; if (!DRY_RUN && (!BOT_TOKEN || !CHAT_ID)) { console.error("[watcher] Missing TELEGRAM_BOT_TOKEN or TELEGRAM_CHAT_ID"); @@ -23,8 +25,7 @@ if (!DRY_RUN && (!BOT_TOKEN || !CHAT_ID)) { process.exit(1); } -let prevSide = null; -let lastSentAt = 0; +let lastSentWindowId = null; let lastSentTs = null; async function send(text) { @@ -94,7 +95,10 @@ function readLast() { if (lines.length < 2) return null; const hdr = lines[0].split(","); const row = lines[lines.length - 1].split(","); - return { hdr, row, rec: row[hdr.indexOf("recommendation")] || "" }; + const ts = row[hdr.indexOf("timestamp")] || null; + const tsMs = ts ? Date.parse(ts) : NaN; + const windowId = Number.isFinite(tsMs) ? Math.floor(tsMs / WINDOW_MS) : null; + return { hdr, row, ts, windowId, rec: row[hdr.indexOf("recommendation")] || "" }; } function watch() { @@ -103,33 +107,22 @@ function watch() { setTimeout(watch, 1000); return; } - console.log(`[watcher] watching ${CSV_PATH} (cooldown ${COOLDOWN_MS}ms${DRY_RUN ? ", DRY_RUN" : ""})`); + console.log(`[watcher] watching ${CSV_PATH} (window ${WINDOW_MS / 60_000}min${DRY_RUN ? ", DRY_RUN" : ""})`); fs.watch(CSV_PATH, { persistent: true }, () => { setTimeout(async () => { try { const data = readLast(); - if (!data) return; - const isEnter = data.rec.includes(":"); - const side = isEnter ? data.rec.split(":")[0] : null; - if (!side) { - prevSide = null; - return; - } - const [, phase, strength] = data.rec.split(":"); - const ts = data.row[data.hdr.indexOf("timestamp")]; - const flipped = side !== prevSide; - const cooled = Date.now() - lastSentAt > COOLDOWN_MS; - const newRow = ts !== lastSentTs; - if (flipped && cooled && newRow) { + if (!data || data.windowId === null || !data.rec.includes(":")) return; + const [side, phase, strength] = data.rec.split(":"); + if (data.windowId !== lastSentWindowId && data.ts !== lastSentTs) { const slug = getCurrentSlug(); console.log("[watcher] slug for push:", slug); const msg = buildMessage(data.hdr, data.row, side, phase, strength, slug); await send(msg); - lastSentAt = Date.now(); - lastSentTs = ts; + lastSentWindowId = data.windowId; + lastSentTs = data.ts; } - prevSide = side; } catch (e) { console.error("[watcher] error:", e.message); }