Sessions 5-7a: 955 tests, deployment ready
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Steam detection — flags lines that move 1+ points in <2 hours.
|
||||
*
|
||||
* Inputs: a stream of { prop_key, book, line, odds, recorded_at } samples.
|
||||
* The orchestrator persists samples to `line_history` and calls check() with
|
||||
* the rolling window for tonight's slate.
|
||||
*/
|
||||
|
||||
const TWO_HOURS_MS = 2 * 60 * 60_000;
|
||||
const STEAM_THRESHOLD = 1;
|
||||
|
||||
/**
|
||||
* @param {Array<{prop_key:string, book:string, line:number, odds:number|null, recorded_at:string|number}>} samples
|
||||
* @returns {Array<{prop_key:string, book:string, from_line:number, to_line:number, delta:number, duration_ms:number, started_at:string, ended_at:string}>}
|
||||
*/
|
||||
function check(samples) {
|
||||
if (!Array.isArray(samples) || samples.length === 0) return [];
|
||||
|
||||
// Group samples by prop_key + book and sort chronologically.
|
||||
const buckets = new Map();
|
||||
for (const s of samples) {
|
||||
const k = `${s.prop_key}|${s.book}`;
|
||||
if (!buckets.has(k)) buckets.set(k, []);
|
||||
buckets.get(k).push({ ...s, t: new Date(s.recorded_at).getTime() });
|
||||
}
|
||||
|
||||
const flags = [];
|
||||
for (const [key, rows] of buckets.entries()) {
|
||||
rows.sort((a, b) => a.t - b.t);
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
// Walk forward in time and stop as soon as the gap > window.
|
||||
const start = rows[i];
|
||||
for (let j = i + 1; j < rows.length; j++) {
|
||||
const end = rows[j];
|
||||
if (end.t - start.t > TWO_HOURS_MS) break;
|
||||
const delta = end.line - start.line;
|
||||
if (Math.abs(delta) >= STEAM_THRESHOLD) {
|
||||
const [propKey, book] = key.split('|');
|
||||
flags.push({
|
||||
prop_key: propKey,
|
||||
book,
|
||||
from_line: start.line,
|
||||
to_line: end.line,
|
||||
delta,
|
||||
duration_ms: end.t - start.t,
|
||||
started_at: new Date(start.t).toISOString(),
|
||||
ended_at: new Date(end.t).toISOString(),
|
||||
});
|
||||
break; // one flag per starting sample
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
module.exports = { check, TWO_HOURS_MS, STEAM_THRESHOLD };
|
||||
Reference in New Issue
Block a user