import { BaseStrategy } from './base.js'; export class SniperReversalStrategy extends BaseStrategy { constructor(config = {}) { super('sniper-reversal', { triggerPct: config.triggerPct || 95, // Bet against a 95% favorite minsLeft: config.minsLeft || 3, // Only in the last 3 minutes betSize: config.betSize || 1, // Cheap lotto tickets cooldownMs: config.cooldownMs || 60000, ...config }); this.lastTradeTime = 0; this.lastTradeTicker = null; } evaluate(state) { if (!state || !this.enabled || !state.closeTime) return null; const now = Date.now(); if (now - this.lastTradeTime < this.config.cooldownMs) return null; if (state.ticker === this.lastTradeTicker) return null; const timeLeftMs = new Date(state.closeTime).getTime() - now; const minsLeft = timeLeftMs / 60000; // Only strike in the final minutes if (minsLeft > this.config.minsLeft || minsLeft <= 0) return null; const { yesPct, noPct } = state; const trigger = this.config.triggerPct; let signal = null; if (yesPct >= trigger && noPct > 0) { signal = { strategy: this.name, side: 'no', price: noPct, size: this.config.betSize, reason: `Buzzer beater No at ${noPct}¢ (Yes is ${yesPct}%) with ${minsLeft.toFixed(1)}m left`, ticker: state.ticker }; } else if (noPct >= trigger && yesPct > 0) { signal = { strategy: this.name, side: 'yes', price: yesPct, size: this.config.betSize, reason: `Buzzer beater Yes at ${yesPct}¢ (No is ${noPct}%) with ${minsLeft.toFixed(1)}m left`, ticker: state.ticker }; } if (signal) { this.lastTradeTime = now; this.lastTradeTicker = state.ticker; } return signal; } }