93 lines
3.2 KiB
TypeScript
93 lines
3.2 KiB
TypeScript
import { ExecutionManager } from '../src/services/executionManager.js';
|
|
import { TradeMonitor } from '../src/services/tradeMonitor.js';
|
|
import { SignalDirection, MarketContext, RuleResult } from '../src/strategies/rules/types.js';
|
|
import { IExchangeConnector } from '../src/connectors/types.js';
|
|
|
|
async function testTrailAndHold() {
|
|
console.log('--- Trailing Guard & Signal Exit Test Start ---');
|
|
|
|
// 1. Mock Exchange
|
|
const mockExchange: any = {
|
|
getPosition: async () => ({ side: 'long', qty: '1', avg_entry_price: '10000' }),
|
|
placeOrder: async (sym: string, side: string) => {
|
|
console.log(`[Mock] Order Placed: ${side} for ${sym}`);
|
|
return { id: 'test-exit-id' };
|
|
},
|
|
fetchOHLCV: async () => [{ close: 10150 }] // 1.5% profit mock price
|
|
};
|
|
|
|
const manager = new ExecutionManager(mockExchange as any);
|
|
const monitor = new TradeMonitor(mockExchange as any, manager);
|
|
|
|
const symbol = 'BTC/USD';
|
|
const entryPrice = 10000;
|
|
|
|
// --- TEST 1: Signal Reversal Exit ---
|
|
console.log('\n--- Scenario 1: Signal Reversal ---');
|
|
(manager as any).activeTraders.set(symbol, {
|
|
side: SignalDirection.BUY,
|
|
entryPrice: entryPrice,
|
|
size: 1,
|
|
stopLoss: 9000,
|
|
takeProfit: 10100, // 1% target
|
|
peakPrice: entryPrice
|
|
});
|
|
|
|
const sellSignal: RuleResult = {
|
|
ruleName: 'ReverseSignal',
|
|
signal: SignalDirection.SELL,
|
|
passed: true,
|
|
reason: 'Trend flipped'
|
|
};
|
|
const context: MarketContext = {
|
|
currentPrice: 10050,
|
|
candles4h: [],
|
|
candles1h: [],
|
|
candles15m: [],
|
|
change24h: 0,
|
|
changeToday: 0,
|
|
session: 'NY',
|
|
isMajorSession: true,
|
|
volatility: 'Low',
|
|
latestSignal: SignalDirection.BUY
|
|
};
|
|
|
|
console.log('Action: Sending SELL signal while in BUY trade...');
|
|
await manager.handleSignal(symbol, sellSignal, context);
|
|
|
|
if (!(manager as any).activeTraders.has(symbol)) {
|
|
console.log('✅ PASS: Trade exited on Signal Flip.');
|
|
} else {
|
|
console.log('❌ FAIL: Trade still active after Signal Flip.');
|
|
}
|
|
|
|
// --- TEST 2: Trailing Profit Guard ---
|
|
console.log('\n--- Scenario 2: Trailing Profit Guard ---');
|
|
// Reset state
|
|
(manager as any).activeTraders.set(symbol, {
|
|
side: SignalDirection.BUY,
|
|
entryPrice: entryPrice,
|
|
size: 1,
|
|
stopLoss: 9000,
|
|
takeProfit: 10100, // 1% target
|
|
peakPrice: 10150, // Peak reached
|
|
profitGuardActive: true
|
|
});
|
|
|
|
// Mock price pullback (0.2% pullback from 10150 peak -> 10129)
|
|
mockExchange.fetchOHLCV = async () => [{ close: 10120 }];
|
|
|
|
console.log('Action: Simulating price pullback (0.3%) after 1.5% run...');
|
|
await (monitor as any).checkOpenPositions();
|
|
|
|
if (!(manager as any).activeTraders.has(symbol)) {
|
|
console.log('✅ PASS: Trailing guard triggered exit on pullback.');
|
|
} else {
|
|
console.log('❌ FAIL: Trailing guard failed to trigger exit.');
|
|
}
|
|
|
|
console.log('\n--- Trailing Guard & Signal Exit Test End ---');
|
|
}
|
|
|
|
testTrailAndHold().catch(console.error);
|