From 0019f088c42b05fa030aff4ba6178518e2645f47 Mon Sep 17 00:00:00 2001 From: multipleof4 Date: Sun, 15 Mar 2026 13:08:51 -0700 Subject: [PATCH] =?UTF-8?q?Feat:=20Threshold=20strategy=20=E2=80=94=20cont?= =?UTF-8?q?rarian=20bet=20at=20extremes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/strategies/threshold.js | 70 +++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 lib/strategies/threshold.js diff --git a/lib/strategies/threshold.js b/lib/strategies/threshold.js new file mode 100644 index 0000000..ecea61f --- /dev/null +++ b/lib/strategies/threshold.js @@ -0,0 +1,70 @@ +import { BaseStrategy } from './base.js'; + +/** + * Threshold (Contrarian) Strategy + * + * Logic: + * - If one side goes above a high threshold (e.g. 65%), bet the other. + * - Fixed bet size — no progression. + * - Simple mean-reversion assumption for short-term BTC markets. + */ +export class ThresholdStrategy extends BaseStrategy { + constructor(config = {}) { + super('threshold', { + triggerPct: config.triggerPct || 65, + betSize: config.betSize || 1, + cooldownMs: config.cooldownMs || 90000, + ...config + }); + + this.lastTradeTime = 0; + this.lastTradeTicker = null; + } + + evaluate(state) { + if (!state || !this.enabled) return null; + + const now = Date.now(); + if (now - this.lastTradeTime < this.config.cooldownMs) return null; + if (state.ticker === this.lastTradeTicker) return null; + + const { yesPct, noPct } = state; + const trigger = this.config.triggerPct; + + let signal = null; + + if (yesPct >= trigger) { + signal = { + strategy: this.name, + side: 'no', + price: noPct, + size: this.config.betSize, + reason: `Yes at ${yesPct}% (≥${trigger}%), contrarian No at ${noPct}¢`, + ticker: state.ticker + }; + } else if (noPct >= trigger) { + signal = { + strategy: this.name, + side: 'yes', + price: yesPct, + size: this.config.betSize, + reason: `No at ${noPct}% (≥${trigger}%), contrarian Yes at ${yesPct}¢`, + ticker: state.ticker + }; + } + + if (signal) { + this.lastTradeTime = now; + this.lastTradeTicker = state.ticker; + } + + return signal; + } + + toJSON() { + return { + ...super.toJSON(), + lastTradeTicker: this.lastTradeTicker + }; + } +}