/** * TP1 Detection Tests * * Tests for Take Profit 1 detection in Position Manager. * TP1 is calculated as ATR × 2.0 (typically ~0.86% at ATR 0.43) * * Key behaviors tested: * - LONG: TP1 triggers when price >= tp1Price * - SHORT: TP1 triggers when price <= tp1Price * - Must NOT trigger below threshold * - Must NOT trigger when price moves against position */ import { createLongTrade, createShortTrade, TEST_DEFAULTS, calculateExpectedProfitPercent } from '../../helpers/trade-factory' describe('TP1 Detection', () => { // Test the shouldTakeProfit1 logic extracted from Position Manager // We test the pure calculation logic rather than the full Position Manager function shouldTakeProfit1(price: number, trade: { direction: 'long' | 'short', tp1Price: number }): boolean { if (trade.direction === 'long') { return price >= trade.tp1Price } else { return price <= trade.tp1Price } } describe('LONG positions', () => { it('should detect TP1 when price reaches +0.86% (ATR 0.43 × 2.0)', () => { // Test data: entry $140, TP1 at $141.20 (+0.86%) const trade = createLongTrade() expect(trade.tp1Price).toBe(TEST_DEFAULTS.long.tp1) // Price at TP1 should trigger const result = shouldTakeProfit1(141.20, trade) expect(result).toBe(true) // Verify profit calculation const profitPercent = calculateExpectedProfitPercent(140, 141.20, 'long') expect(profitPercent).toBeCloseTo(0.857, 1) // ~0.86% }) it('should detect TP1 when price exceeds tp1Price', () => { const trade = createLongTrade() // Price above TP1 should also trigger const result = shouldTakeProfit1(142.00, trade) expect(result).toBe(true) }) it('should NOT detect TP1 when price is below threshold (+0.5%)', () => { const trade = createLongTrade() // Price at +0.5% ($140.70) should NOT trigger TP1 const result = shouldTakeProfit1(140.70, trade) expect(result).toBe(false) // Verify profit percent is below TP1 threshold const profitPercent = calculateExpectedProfitPercent(140, 140.70, 'long') expect(profitPercent).toBeCloseTo(0.5, 2) expect(profitPercent).toBeLessThan(0.86) }) it('should NOT detect TP1 when price moves against position (negative)', () => { const trade = createLongTrade() // Price drop for LONG should NOT trigger TP1 const result = shouldTakeProfit1(139.00, trade) expect(result).toBe(false) // Verify this is a loss const profitPercent = calculateExpectedProfitPercent(140, 139.00, 'long') expect(profitPercent).toBeLessThan(0) }) it('should NOT detect TP1 at entry price', () => { const trade = createLongTrade() const result = shouldTakeProfit1(140.00, trade) expect(result).toBe(false) }) }) describe('SHORT positions', () => { it('should detect TP1 when price reaches -0.86% (ATR 0.43 × 2.0)', () => { // Test data: entry $140, TP1 at $138.80 (-0.86%) const trade = createShortTrade() expect(trade.tp1Price).toBe(TEST_DEFAULTS.short.tp1) // Price at TP1 should trigger const result = shouldTakeProfit1(138.80, trade) expect(result).toBe(true) // Verify profit calculation (SHORT profits when price drops) const profitPercent = calculateExpectedProfitPercent(140, 138.80, 'short') expect(profitPercent).toBeCloseTo(0.857, 1) // ~0.86% }) it('should detect TP1 when price is below tp1Price', () => { const trade = createShortTrade() // Price below TP1 should also trigger (better for short) const result = shouldTakeProfit1(138.00, trade) expect(result).toBe(true) }) it('should NOT detect TP1 when price is above threshold (-0.5%)', () => { const trade = createShortTrade() // Price at -0.5% ($139.30) should NOT trigger TP1 const result = shouldTakeProfit1(139.30, trade) expect(result).toBe(false) // Verify profit percent is below TP1 threshold const profitPercent = calculateExpectedProfitPercent(140, 139.30, 'short') expect(profitPercent).toBeCloseTo(0.5, 2) expect(profitPercent).toBeLessThan(0.86) }) it('should NOT detect TP1 when price moves against position (rises)', () => { const trade = createShortTrade() // Price rise for SHORT should NOT trigger TP1 const result = shouldTakeProfit1(141.00, trade) expect(result).toBe(false) // Verify this is a loss for SHORT const profitPercent = calculateExpectedProfitPercent(140, 141.00, 'short') expect(profitPercent).toBeLessThan(0) }) it('should NOT detect TP1 at entry price', () => { const trade = createShortTrade() const result = shouldTakeProfit1(140.00, trade) expect(result).toBe(false) }) }) describe('Edge cases', () => { it('should handle exact TP1 price (boundary condition)', () => { const longTrade = createLongTrade() const shortTrade = createShortTrade() // Exact TP1 price should trigger expect(shouldTakeProfit1(longTrade.tp1Price, longTrade)).toBe(true) expect(shouldTakeProfit1(shortTrade.tp1Price, shortTrade)).toBe(true) }) it('should handle custom TP1 prices', () => { const trade = createLongTrade({ tp1Price: 145.00 }) expect(trade.tp1Price).toBe(145.00) expect(shouldTakeProfit1(144.99, trade)).toBe(false) expect(shouldTakeProfit1(145.00, trade)).toBe(true) expect(shouldTakeProfit1(145.01, trade)).toBe(true) }) it('should work with different entry prices', () => { // ETH-PERP style entry at $3500 const trade = createLongTrade({ entryPrice: 3500, tp1Price: 3530, // +0.86% }) expect(shouldTakeProfit1(3529, trade)).toBe(false) expect(shouldTakeProfit1(3530, trade)).toBe(true) }) }) })