From d54b11293d8ba38562d2d4bcc5d6dfd853cf847b Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 9 Jun 2026 20:28:43 +0000 Subject: [PATCH] refactor: Review-Fixes Strategie (unbenutzter Param, Range-Guard, Ratchet-Test) --- src/server/strategy/chandelier.test.ts | 7 +++++++ src/server/strategy/donchian-trend.test.ts | 8 ++++---- src/server/strategy/donchian-trend.ts | 3 ++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/server/strategy/chandelier.test.ts b/src/server/strategy/chandelier.test.ts index c35fb26..34d7d85 100644 --- a/src/server/strategy/chandelier.test.ts +++ b/src/server/strategy/chandelier.test.ts @@ -20,3 +20,10 @@ test('NaN-ATR lässt Stop unverändert', () => { expect(r.highestHigh).toBe(120); expect(r.stop).toBe(104); }); + +test('Stop ratchtet hoch wenn ATR schrumpft, auch ohne neues Hoch', () => { + // hh bleibt 110, ATR schrumpft von 3 auf 1 → Stop 110−3 = 107 > vorher 104 + const r = updateChandelier({ highestHigh: 110, stop: 104 }, 105, 1, 3); + expect(r.highestHigh).toBe(110); + expect(r.stop).toBe(107); +}); diff --git a/src/server/strategy/donchian-trend.test.ts b/src/server/strategy/donchian-trend.test.ts index b37ca81..5ab14d7 100644 --- a/src/server/strategy/donchian-trend.test.ts +++ b/src/server/strategy/donchian-trend.test.ts @@ -19,7 +19,7 @@ function breakoutSeries(): Candle[] { test('Long-Signal bei Donchian-Breakout über Trend-EMA', () => { const c4h = breakoutSeries(); - const ev = evaluateAt(c4h, computeIndicators(c4h, P), c4h.length - 1, P); + const ev = evaluateAt(c4h, computeIndicators(c4h, P), c4h.length - 1); expect(ev.signal).toBe('long'); expect(ev.blockedBy).toBeNull(); expect(ev.donchianHigh).toBe(17); @@ -29,7 +29,7 @@ test('Long-Signal bei Donchian-Breakout über Trend-EMA', () => { test('blockiert unter Donchian-High', () => { const c4h = breakoutSeries(); c4h[c4h.length - 1].close = 16.9; // unter 17 - const ev = evaluateAt(c4h, computeIndicators(c4h, P), c4h.length - 1, P); + const ev = evaluateAt(c4h, computeIndicators(c4h, P), c4h.length - 1); expect(ev.signal).toBeNull(); expect(ev.blockedBy).toBe('below_donchian'); }); @@ -46,14 +46,14 @@ test('blockiert unter Trend-EMA (Bärenmarkt-Filter)', () => { s.push(c(75, 76, 74, 75, 6)); // Index 7: Donchian[7] = max(76,76,76) = 76, EMA5 ≈ 80, Close 77 > Donchian aber < EMA s.push(c(77, 80, 76, 77, 7)); - const ev = evaluateAt(s, computeIndicators(s, P), s.length - 1, P); + const ev = evaluateAt(s, computeIndicators(s, P), s.length - 1); expect(ev.signal).toBeNull(); expect(ev.blockedBy).toBe('below_trend_ema'); }); test('blockiert bei zu wenig Daten', () => { const c4h = breakoutSeries().slice(0, 4); - const ev = evaluateAt(c4h, computeIndicators(c4h, P), c4h.length - 1, P); + const ev = evaluateAt(c4h, computeIndicators(c4h, P), c4h.length - 1); expect(ev.blockedBy).toBe('insufficient_data'); }); diff --git a/src/server/strategy/donchian-trend.ts b/src/server/strategy/donchian-trend.ts index c87fdf0..3040ac6 100644 --- a/src/server/strategy/donchian-trend.ts +++ b/src/server/strategy/donchian-trend.ts @@ -42,11 +42,12 @@ export function computeIndicators(c4h: Candle[], p: StrategyParams): IndicatorSe } /** Bewertet die (abgeschlossene) 4h-Candle an Index i. */ -export function evaluateAt(c4h: Candle[], ind: IndicatorSet, i: number, p: StrategyParams): Evaluation { +export function evaluateAt(c4h: Candle[], ind: IndicatorSet, i: number): Evaluation { const close = c4h[i]?.close ?? NaN; const base = { close, atr: ind.atr[i], donchianHigh: ind.donchianHigh[i], trendEma: ind.trendEma[i] }; if ( i < 0 || + i >= c4h.length || Number.isNaN(ind.trendEma[i]) || Number.isNaN(ind.donchianHigh[i]) || Number.isNaN(ind.atr[i])