fix: Preis-Lücken-Warnung, Pair-Typisierung, Nebenläufigkeits-Doku im Poller (Review Task 6)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,7 @@ import { getCandles } from '../market/candle-store';
|
||||
import { fetchTransfers, getBlockNumber, getBlockTs } from './onchain';
|
||||
import { matchCoins, parseTruthFeed } from './truth';
|
||||
import { COIN_KEYWORDS, MIN_NOTIONAL_USD, TRUTH_DEDUPE_MS, TRUTH_FEED_URL } from './watchlist';
|
||||
import type { Pair } from '../types';
|
||||
|
||||
const M15 = 15 * 60 * 1000;
|
||||
/** Obergrenze Blöcke je Zyklus (~4 getLogs-Calls); Ethereum macht ~25 Blöcke/5min — reichlich Aufholpuffer. */
|
||||
@@ -33,9 +34,9 @@ export function dedupeTruthEvents(
|
||||
return batch.filter((e) => accepted.has(e.url));
|
||||
}
|
||||
|
||||
/** Letzter 15m-Close ≤ ts als USD-Proxy (USDT≈USD). null wenn keine Candle vorhanden. */
|
||||
async function priceAt(instrument: string, ts: number): Promise<number | null> {
|
||||
const candles = await getCandles(instrument as any, ts - 24 * 3600_000, ts + M15);
|
||||
/** Close der jüngsten Candle im Fenster [ts−24h, ts+15m) als USD-Proxy (USDT≈USD). null wenn keine Candle vorhanden. */
|
||||
async function priceAt(instrument: Pair, ts: number): Promise<number | null> {
|
||||
const candles = await getCandles(instrument, ts - 24 * 3600_000, ts + M15);
|
||||
return candles.length > 0 ? candles[candles.length - 1].close : null;
|
||||
}
|
||||
|
||||
@@ -58,6 +59,10 @@ export async function pollOnchain(): Promise<number> {
|
||||
if (!blockTs.has(t.blockNumber)) blockTs.set(t.blockNumber, await getBlockTs(t.blockNumber));
|
||||
const ts = blockTs.get(t.blockNumber)!;
|
||||
const price = t.instrument ? await priceAt(t.instrument, ts) : null;
|
||||
if (t.instrument && price === null) {
|
||||
// Candle-Lücke (frisches Listing / Backfill fehlt) — sichtbar machen statt still verwerfen
|
||||
console.warn(`Trump-Transfer ohne Preis verworfen: ${t.symbol} ${t.amount} (${t.txHash})`);
|
||||
}
|
||||
if (!passesNotional(t.amount, price)) continue;
|
||||
await db
|
||||
.insert(trumpEvents)
|
||||
@@ -105,7 +110,11 @@ export async function pollTruth(): Promise<number> {
|
||||
return inserted;
|
||||
}
|
||||
|
||||
/** Beide Quellen, Fehler isoliert (eine tote Quelle stoppt die andere nicht). */
|
||||
/**
|
||||
* Beide Quellen, Fehler isoliert (eine tote Quelle stoppt die andere nicht).
|
||||
* Annahme: läuft nie nebenläufig (5-min-Loop ist seriell, Engine hat cycling-Guard) —
|
||||
* das Truth-Dedupe liest existing vor den Inserts und wäre bei Parallelläufen lückenhaft.
|
||||
*/
|
||||
export async function pollSignals(): Promise<void> {
|
||||
const results = await Promise.allSettled([pollOnchain(), pollTruth()]);
|
||||
for (const r of results) {
|
||||
|
||||
Reference in New Issue
Block a user