diff --git a/lib/strategies/late-momentum.js b/lib/strategies/late-momentum.js index 057f89c..3f53ea6 100644 --- a/lib/strategies/late-momentum.js +++ b/lib/strategies/late-momentum.js @@ -4,8 +4,8 @@ import { BaseStrategy } from './base.js'; * Late Momentum Strategy * * Rules: - * - Only buys YES momentum - * - Requires YES price >= triggerPct (default 75) + * - Buys momentum on YES or NO + * - Requires side price >= triggerPct (default 75) * - Only allowed after first 5 minutes of market lifecycle * - Default window: elapsed minute 5 through 15 */ @@ -44,28 +44,37 @@ export class LateMomentumStrategy extends BaseStrategy { const elapsedMin = (this.config.marketDurationMin * 60000 - timeLeftMs) / 60000; if (!Number.isFinite(elapsedMin)) return null; - // Skip first 5 minutes; trade only in configured late window. + // Skip first minutes; trade only in configured late window. if (elapsedMin < this.config.minElapsedMin || elapsedMin > this.config.maxElapsedMin) return null; const yesPct = Number(state.yesPct); - if (!Number.isFinite(yesPct)) return null; + const noPct = Number(state.noPct); + if (!Number.isFinite(yesPct) || !Number.isFinite(noPct)) return null; - if (yesPct >= this.config.triggerPct && yesPct < 99) { - const signal = { - strategy: this.name, - side: 'yes', - price: yesPct, - maxPrice: Math.min(yesPct + this.config.slippage, 95), - size: this.config.betSize, - reason: `Late momentum: t+${elapsedMin.toFixed(1)}m, YES @ ${yesPct}¢`, - ticker: state.ticker - }; + const trigger = this.config.triggerPct; + const candidates = []; - track.time = now; - track.ticker = state.ticker; - return signal; - } + if (yesPct >= trigger && yesPct < 99) candidates.push({ side: 'yes', pct: yesPct }); + if (noPct >= trigger && noPct < 99) candidates.push({ side: 'no', pct: noPct }); - return null; + if (!candidates.length) return null; + + // Prefer the stronger momentum side if both qualify. + candidates.sort((a, b) => b.pct - a.pct); + const pick = candidates[0]; + + const signal = { + strategy: this.name, + side: pick.side, + price: pick.pct, + maxPrice: Math.min(pick.pct + this.config.slippage, 95), + size: this.config.betSize, + reason: `Late momentum: t+${elapsedMin.toFixed(1)}m, ${pick.side.toUpperCase()} @ ${pick.pct}¢`, + ticker: state.ticker + }; + + track.time = now; + track.ticker = state.ticker; + return signal; } }