import { describe, it, expect } from 'vitest';
/**
* Unit tests for signal detection constants and logic.
* Since signals.js has side effects and requires external deps,
* we test the exported pure helpers and constants.
*/
describe('Signal Constants (sanity checks)', () => {
// Import just to verify module loads without crashing
// signals.js uses require() for deps that might not exist in test,
// so we test the liq-sweep module which is more testable
it('VOL_SMA_PERIOD and thresholds are sane', () => {
// These are documented in CLAUDE.md
const VOL_SMA_PERIOD = 20;
const VOL_MIN_RATIO = 2.0;
const MIN_VOLUME_24H_USD = 30_000_000;
expect(VOL_SMA_PERIOD).toBeGreaterThan(0);
expect(VOL_MIN_RATIO).toBeGreaterThanOrEqual(2);
expect(MIN_VOLUME_24H_USD).toBeGreaterThanOrEqual(1_000_000);
});
it('cooldown is at least 30 minutes', () => {
const COOLDOWN_MS = 60 * 60_000; // from signals.js
expect(COOLDOWN_MS).toBeGreaterThanOrEqual(30 * 60_000);
});
});
describe('Volume Spike Detection Logic', () => {
// Simulate the core vol_spike logic without external deps
function detectVolSpike(volumes, currentVol, minRatio = 2.0) {
if (!volumes || volumes.length === 0) return null;
const avg = volumes.reduce((a, b) => a + b, 0) / volumes.length;
if (avg === 0) return null;
const ratio = currentVol / avg;
if (ratio >= minRatio) {
return { ratio, avg, confidence: Math.min(100, 30 + ratio * 10) };
}
return null;
}
it('detects spike when volume exceeds ratio', () => {
const history = Array(20).fill(1000);
const result = detectVolSpike(history, 5000, 2.0);
expect(result).not.toBeNull();
expect(result.ratio).toBe(5);
});
it('returns null when volume is below ratio', () => {
const history = Array(20).fill(1000);
const result = detectVolSpike(history, 1500, 2.0);
expect(result).toBeNull();
});
it('confidence is capped at 100', () => {
const history = Array(20).fill(100);
const result = detectVolSpike(history, 10000, 2.0); // 100x
expect(result.confidence).toBeLessThanOrEqual(100);
});
it('handles zero average gracefully', () => {
const history = Array(20).fill(0);
const result = detectVolSpike(history, 1000, 2.0);
expect(result).toBeNull();
});
it('handles empty history', () => {
expect(detectVolSpike([], 1000)).toBeNull();
expect(detectVolSpike(null, 1000)).toBeNull();
});
});
describe('OI Divergence Detection Logic', () => {
function detectOiDivergence(priceChangePct, oiChangePct, thresholds = { price: 1.0, oi: 2.0 }) {
const absPriceChange = Math.abs(priceChangePct);
const absOiChange = Math.abs(oiChangePct);
if (absPriceChange < thresholds.price || absOiChange < thresholds.oi) {
return null;
}
// Price up + OI down = exhaustion (shorts closing)
if (priceChangePct > 0 && oiChangePct < 0) {
return { type: 'exhaustion_long', priceChangePct, oiChangePct };
}
// Price down + OI down = exhaustion (longs closing)
if (priceChangePct < 0 && oiChangePct < 0) {
return { type: 'exhaustion_short', priceChangePct, oiChangePct };
}
// Price up + OI up = accumulation (new longs)
if (priceChangePct > 0 && oiChangePct > 0) {
return { type: 'accumulation_long', priceChangePct, oiChangePct };
}
// Price down + OI up = accumulation (new shorts)
if (priceChangePct < 0 && oiChangePct > 0) {
return { type: 'accumulation_short', priceChangePct, oiChangePct };
}
return null;
}
it('detects exhaustion_long (price up, OI down)', () => {
const result = detectOiDivergence(2.5, -3.0);
expect(result).not.toBeNull();
expect(result.type).toBe('exhaustion_long');
});
it('detects exhaustion_short (price down, OI down)', () => {
const result = detectOiDivergence(-1.5, -2.5);
expect(result).not.toBeNull();
expect(result.type).toBe('exhaustion_short');
});
it('detects accumulation_long (price up, OI up)', () => {
const result = detectOiDivergence(1.5, 3.0);
expect(result).not.toBeNull();
expect(result.type).toBe('accumulation_long');
});
it('detects accumulation_short (price down, OI up)', () => {
const result = detectOiDivergence(-2.0, 4.0);
expect(result).not.toBeNull();
expect(result.type).toBe('accumulation_short');
});
it('returns null when changes below threshold', () => {
expect(detectOiDivergence(0.5, 1.0)).toBeNull();
expect(detectOiDivergence(0.1, 0.5)).toBeNull();
});
});
📜 Git History
b873b03feat: add deploy/ops scripts, vitest config, and expanded test suite9 weeks ago
Show last diff
Loading...