Feat: Split paper/live tracking, orderbook pricing

This commit is contained in:
2026-03-16 12:30:02 -07:00
parent 2beb261bad
commit 0fc244fcf1

View File

@@ -20,53 +20,57 @@ export class MartingaleAlphaStrategy extends BaseStrategy {
maxPct: config.maxPct || 60, maxPct: config.maxPct || 60,
baseBet: config.baseBet || 1, baseBet: config.baseBet || 1,
maxRounds: config.maxRounds || 3, maxRounds: config.maxRounds || 3,
cooldownMs: config.cooldownMs || 60000, slippage: config.slippage || 3,
cooldownMs: config.cooldownMs || 20000,
...config ...config
}); });
this.round = 0; // 0 = waiting, 1-3 = active round this.round = 0;
this.currentBetSize = this.config.baseBet; this.currentBetSize = this.config.baseBet;
this.lastTradeTime = 0;
this.lastTradeTicker = null;
this.cycleWins = 0; this.cycleWins = 0;
this.cycleLosses = 0; this.cycleLosses = 0;
this.totalCycles = 0; this.totalCycles = 0;
this._lastTrade = {
paper: { time: 0, ticker: null },
live: { time: 0, ticker: null }
};
} }
evaluate(state) { evaluate(state, caller = 'paper') {
if (!state || !this.enabled) return null; if (!state || !this.enabled) return null;
const track = this._lastTrade[caller] || this._lastTrade.paper;
const now = Date.now(); const now = Date.now();
if (now - this.lastTradeTime < this.config.cooldownMs) return null; if (now - track.time < this.config.cooldownMs) return null;
if (state.ticker === this.lastTradeTicker) return null; if (state.ticker === track.ticker) return null;
const { yesPct, noPct } = state; const { yesPct, noPct } = state;
const { minPct, maxPct } = this.config; const { minPct, maxPct } = this.config;
// Only trade when both sides are in the 40-60% range (coin-flip territory)
if (yesPct < minPct || yesPct > maxPct) return null; if (yesPct < minPct || yesPct > maxPct) return null;
if (noPct < minPct || noPct > maxPct) return null; if (noPct < minPct || noPct > maxPct) return null;
// Secure random coin flip: 0 = yes, 1 = no
const flip = crypto.randomInt(0, 2); const flip = crypto.randomInt(0, 2);
const side = flip === 0 ? 'yes' : 'no'; const side = flip === 0 ? 'yes' : 'no';
const price = side === 'yes' ? yesPct : noPct; const price = side === 'yes' ? yesPct : noPct;
const maxPrice = Math.min(price + this.config.slippage, 95);
// Determine bet size based on current round const roundIndex = this.round;
const roundIndex = this.round; // 0, 1, or 2
const betSize = this.config.baseBet * Math.pow(2, roundIndex); const betSize = this.config.baseBet * Math.pow(2, roundIndex);
const signal = { const signal = {
strategy: this.name, strategy: this.name,
side, side,
price, price,
maxPrice,
size: betSize, size: betSize,
reason: `R${roundIndex + 1}/${this.config.maxRounds} coin-flip ${side.toUpperCase()} @ ${price}¢ ($${betSize}) | Market: ${yesPct}/${noPct}`, reason: `R${roundIndex + 1}/${this.config.maxRounds} coin-flip ${side.toUpperCase()} @ ${price}¢ ($${betSize}) | Market: ${yesPct}/${noPct}`,
ticker: state.ticker ticker: state.ticker
}; };
this.lastTradeTime = now; track.time = now;
this.lastTradeTicker = state.ticker; track.ticker = state.ticker;
this.currentBetSize = betSize; this.currentBetSize = betSize;
return signal; return signal;
@@ -100,7 +104,9 @@ export class MartingaleAlphaStrategy extends BaseStrategy {
_resetCycle() { _resetCycle() {
this.round = 0; this.round = 0;
this.currentBetSize = this.config.baseBet; this.currentBetSize = this.config.baseBet;
this.lastTradeTicker = null; // Allow trading same ticker in new cycle // Reset both callers' ticker locks so new cycle can trade same market
this._lastTrade.paper.ticker = null;
this._lastTrade.live.ticker = null;
} }
toJSON() { toJSON() {