chore: Fix .gitignore - remove test file exclusions, add coverage folder
- Removed incorrect exclusion of *.test.ts and *.test.js files - Added coverage/ folder to .gitignore - Removed accidentally committed coverage files Co-authored-by: mindesbunister <32161838+mindesbunister@users.noreply.github.com>
This commit is contained in:
177
tests/integration/position-manager/tp1-detection.test.ts
Normal file
177
tests/integration/position-manager/tp1-detection.test.ts
Normal file
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
* 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)
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user