Your Name
feat: UI improvements and error suppression - Enhanced dashboard and market pages with improved header buttons, logo, and currency symbol display - Stopped animated ticker - Removed pie chart legends - Added error suppressor for external service errors (SSE, Permissions-Policy warnings) - Improved header button prominence and icon appearance - Enhanced logo with glow effects and better design - Fixed currency symbol visibility in market tables
8b7b267
/**
* Comprehensive Testing Suite for Trading System
* Tests all components with mock data and real scenarios
*/
import { IntegratedTradingSystem } from './integrated-trading-system.js';
import { analyzeMarketStructure, detectMomentumDivergences } from './advanced-strategies-v2.js';
import { AdaptiveRegimeDetector, MARKET_REGIMES } from './adaptive-regime-detector.js';
import { NotificationManager } from './enhanced-notification-system.js';
/**
* Test runner
*/
export class TradingSystemTests {
constructor() {
this.results = {
passed: 0,
failed: 0,
total: 0,
tests: []
};
}
/**
* Run all tests
* @returns {Promise<Object>} Test results
*/
async runAll() {
console.log('🧪 Running Trading System Tests...\n');
await this.testMarketStructureAnalysis();
await this.testMomentumDivergence();
await this.testRegimeDetection();
await this.testNotificationSystem();
await this.testIntegratedSystem();
await this.testErrorHandling();
await this.testDataValidation();
await this.testStrategySelection();
return this.getSummary();
}
/**
* Test market structure analysis
*/
async testMarketStructureAnalysis() {
console.log('📊 Testing Market Structure Analysis...');
try {
// Generate bullish trend data
const bullishData = this.generateTrendData('bullish', 100);
const bullishResult = analyzeMarketStructure(bullishData);
this.assert(
'Bullish market structure detected',
bullishResult.structure === 'bullish' || bullishResult.structure === 'bullish-weakening',
`Expected bullish structure, got: ${bullishResult.structure}`
);
this.assert(
'Order blocks identified',
bullishResult.orderBlocks.length > 0,
`Expected order blocks, got: ${bullishResult.orderBlocks.length}`
);
// Generate bearish trend data
const bearishData = this.generateTrendData('bearish', 100);
const bearishResult = analyzeMarketStructure(bearishData);
this.assert(
'Bearish market structure detected',
bearishResult.structure === 'bearish' || bearishResult.structure === 'bearish-weakening',
`Expected bearish structure, got: ${bearishResult.structure}`
);
// Generate ranging data
const rangingData = this.generateRangingData(100);
const rangingResult = analyzeMarketStructure(rangingData);
this.assert(
'Ranging market detected',
rangingResult.structure === 'ranging' || rangingResult.structure === 'neutral',
`Expected ranging/neutral, got: ${rangingResult.structure}`
);
} catch (error) {
this.fail('Market structure analysis', error);
}
}
/**
* Test momentum divergence detection
*/
async testMomentumDivergence() {
console.log('📈 Testing Momentum Divergence Detection...');
try {
// Generate divergence scenario
const data = this.generateDivergenceData();
const result = detectMomentumDivergences(data);
this.assert(
'Divergences detected',
result.divergences !== undefined,
'Divergence detection returned result'
);
this.assert(
'Signal generated',
['buy', 'sell', 'hold'].includes(result.signal),
`Valid signal: ${result.signal}`
);
this.assert(
'Confidence calculated',
result.confidence >= 0 && result.confidence <= 100,
`Confidence in range: ${result.confidence}`
);
} catch (error) {
this.fail('Momentum divergence detection', error);
}
}
/**
* Test regime detection
*/
async testRegimeDetection() {
console.log('🎯 Testing Regime Detection...');
try {
const detector = new AdaptiveRegimeDetector();
// Test trending bullish
const trendData = this.generateTrendData('bullish', 100);
const trendResult = detector.detectRegime(trendData);
this.assert(
'Trend regime detected',
Object.values(MARKET_REGIMES).includes(trendResult.regime),
`Valid regime: ${trendResult.regime}`
);
this.assert(
'Confidence calculated',
trendResult.confidence >= 0 && trendResult.confidence <= 100,
`Confidence: ${trendResult.confidence}`
);
// Test ranging
const rangeData = this.generateRangingData(100);
const rangeResult = detector.detectRegime(rangeData);
this.assert(
'Ranging regime detected',
rangeResult.regime === MARKET_REGIMES.RANGING || rangeResult.regime === MARKET_REGIMES.CALM,
`Expected ranging/calm, got: ${rangeResult.regime}`
);
// Test volatile
const volatileData = this.generateVolatileData(100);
const volatileResult = detector.detectRegime(volatileData);
this.assert(
'Volatile regime detected',
volatileResult.regime.includes('volatile') || volatileResult.metrics.volatility > 5,
`Volatility: ${volatileResult.metrics.volatility}%`
);
// Test recommended strategies
const strategies = detector.getRecommendedStrategies();
this.assert(
'Strategies recommended',
Array.isArray(strategies) && strategies.length > 0,
`Strategies: ${strategies.length}`
);
} catch (error) {
this.fail('Regime detection', error);
}
}
/**
* Test notification system
*/
async testNotificationSystem() {
console.log('🔔 Testing Notification System...');
try {
const notifManager = new NotificationManager({
enabled: true,
channels: ['browser']
});
// Test signal notification
const signal = {
strategy: 'Test Strategy',
signal: 'buy',
confidence: 85,
entry: 50000,
stopLoss: 48000,
targets: [
{ level: 52000, type: 'TP1', percentage: 50 },
{ level: 54000, type: 'TP2', percentage: 50 }
],
riskRewardRatio: '1:3'
};
const result = await notifManager.sendSignal(signal);
this.assert(
'Signal notification sent',
result.success || result.results?.browser?.success === false, // May fail if browser notifications disabled
`Result: ${JSON.stringify(result)}`
);
// Test validation
const invalidNotif = { title: null };
const validationResult = notifManager.validateNotification(invalidNotif);
this.assert(
'Invalid notification rejected',
!validationResult.valid,
'Validation catches invalid notifications'
);
// Test history
const history = notifManager.getHistory();
this.assert(
'History available',
Array.isArray(history),
'History is an array'
);
} catch (error) {
this.fail('Notification system', error);
}
}
/**
* Test integrated system
*/
async testIntegratedSystem() {
console.log('🎮 Testing Integrated System...');
try {
const system = new IntegratedTradingSystem({
symbol: 'BTC',
strategy: 'ict-market-structure',
enableNotifications: false,
useAdaptiveStrategy: true
});
// Test initialization
this.assert(
'System initialized',
system !== null,
'System object created'
);
// Test status
const status = system.getStatus();
this.assert(
'Status retrieved',
status.isRunning !== undefined,
'Status contains running state'
);
// Test configuration update
system.updateConfig({ symbol: 'ETH' });
this.assert(
'Config updated',
system.config.symbol === 'ETH',
'Symbol updated to ETH'
);
// Test analysis
const sampleData = system.generateSampleData();
const analysis = await system.performAnalysis(sampleData);
this.assert(
'Analysis performed',
analysis.signal !== undefined,
`Signal: ${analysis.signal}`
);
this.assert(
'Confidence calculated',
analysis.confidence >= 0 && analysis.confidence <= 100,
`Confidence: ${analysis.confidence}`
);
// Test performance stats
const stats = system.getPerformanceStats();
this.assert(
'Performance stats available',
stats.totalSignals !== undefined,
'Stats structure valid'
);
} catch (error) {
this.fail('Integrated system', error);
}
}
/**
* Test error handling
*/
async testErrorHandling() {
console.log('🛡️ Testing Error Handling...');
try {
// Test with insufficient data
const shortData = this.generateTrendData('bullish', 10);
try {
const result = analyzeMarketStructure(shortData);
this.assert(
'Handles insufficient data',
result.error !== undefined || result.structure === 'unknown',
'Returns error or default for short data'
);
} catch (e) {
this.pass('Handles insufficient data (threw expected error)');
}
// Test with null data
try {
const result = analyzeMarketStructure(null);
this.assert(
'Handles null data',
result.error !== undefined,
'Returns error for null data'
);
} catch (e) {
this.pass('Handles null data (threw expected error)');
}
// Test with invalid OHLCV data
const invalidData = [
{ timestamp: 123, open: 'invalid', high: 100, low: 90, close: 95, volume: 1000 }
];
try {
const result = analyzeMarketStructure(invalidData);
this.pass('Handles invalid data types');
} catch (e) {
this.pass('Handles invalid data types (threw expected error)');
}
} catch (error) {
this.fail('Error handling', error);
}
}
/**
* Test data validation
*/
async testDataValidation() {
console.log('✅ Testing Data Validation...');
try {
// Test valid OHLCV data
const validData = {
timestamp: Date.now(),
open: 50000,
high: 51000,
low: 49000,
close: 50500,
volume: 1000000
};
this.assert(
'Valid OHLCV data',
this.isValidOHLCV(validData),
'Valid data passes validation'
);
// Test invalid OHLCV data
const invalidData = {
timestamp: Date.now(),
open: -1,
high: 51000,
low: 49000,
close: 50500,
volume: 1000000
};
this.assert(
'Invalid OHLCV data rejected',
!this.isValidOHLCV(invalidData),
'Invalid data fails validation'
);
// Test data with missing fields
const incompleteData = {
timestamp: Date.now(),
open: 50000,
high: 51000
};
this.assert(
'Incomplete data rejected',
!this.isValidOHLCV(incompleteData),
'Incomplete data fails validation'
);
} catch (error) {
this.fail('Data validation', error);
}
}
/**
* Test strategy selection
*/
async testStrategySelection() {
console.log('🎲 Testing Strategy Selection...');
try {
const strategies = IntegratedTradingSystem.getAvailableStrategies();
this.assert(
'Strategies available',
strategies.advanced !== undefined && strategies.hybrid !== undefined,
'Both strategy types available'
);
this.assert(
'Advanced strategies present',
Object.keys(strategies.advanced).length > 0,
`${Object.keys(strategies.advanced).length} advanced strategies`
);
this.assert(
'Hybrid strategies present',
Object.keys(strategies.hybrid).length > 0,
`${Object.keys(strategies.hybrid).length} hybrid strategies`
);
// Test regime-based strategy recommendation
const detector = new AdaptiveRegimeDetector();
const data = this.generateTrendData('bullish', 100);
const regimeResult = detector.detectRegime(data);
const recommended = detector.getRecommendedStrategies();
this.assert(
'Strategies recommended for regime',
Array.isArray(recommended) && recommended.length > 0,
`${recommended.length} strategies recommended for ${regimeResult.regime}`
);
} catch (error) {
this.fail('Strategy selection', error);
}
}
/**
* Assert helper
*/
assert(name, condition, message) {
this.results.total++;
if (condition) {
this.pass(name);
} else {
this.fail(name, new Error(message));
}
}
/**
* Pass helper
*/
pass(name) {
this.results.passed++;
this.results.tests.push({
name,
status: 'passed',
message: '✅ Passed'
});
console.log(` ✅ ${name}`);
}
/**
* Fail helper
*/
fail(name, error) {
this.results.failed++;
this.results.tests.push({
name,
status: 'failed',
message: `❌ ${error.message}`,
error: error.stack
});
console.error(` ❌ ${name}: ${error.message}`);
}
/**
* Get test summary
*/
getSummary() {
console.log('\n' + '='.repeat(50));
console.log('📊 Test Summary');
console.log('='.repeat(50));
console.log(`Total: ${this.results.total}`);
console.log(`Passed: ${this.results.passed} ✅`);
console.log(`Failed: ${this.results.failed} ❌`);
console.log(`Success Rate: ${((this.results.passed / this.results.total) * 100).toFixed(1)}%`);
console.log('='.repeat(50) + '\n');
return this.results;
}
/**
* Generate trending data
*/
generateTrendData(direction, length) {
const data = [];
let price = 50000;
const trendFactor = direction === 'bullish' ? 1.002 : 0.998;
for (let i = 0; i < length; i++) {
const volatility = price * 0.01;
const open = price;
price = price * trendFactor;
const close = price + (Math.random() - 0.5) * volatility;
const high = Math.max(open, close) + Math.random() * volatility * 0.3;
const low = Math.min(open, close) - Math.random() * volatility * 0.3;
const volume = 500000 + Math.random() * 500000;
data.push({
timestamp: Date.now() - (length - i) * 3600000,
open, high, low, close, volume
});
price = close;
}
return data;
}
/**
* Generate ranging data
*/
generateRangingData(length) {
const data = [];
const basePrice = 50000;
const rangeSize = basePrice * 0.02;
for (let i = 0; i < length; i++) {
const price = basePrice + (Math.random() - 0.5) * rangeSize;
const volatility = price * 0.005;
const open = price;
const close = price + (Math.random() - 0.5) * volatility;
const high = Math.max(open, close) + Math.random() * volatility;
const low = Math.min(open, close) - Math.random() * volatility;
const volume = 500000 + Math.random() * 500000;
data.push({
timestamp: Date.now() - (length - i) * 3600000,
open, high, low, close, volume
});
}
return data;
}
/**
* Generate volatile data
*/
generateVolatileData(length) {
const data = [];
let price = 50000;
for (let i = 0; i < length; i++) {
const volatility = price * 0.05; // High volatility
const open = price;
const close = price + (Math.random() - 0.5) * volatility * 2;
const high = Math.max(open, close) + Math.random() * volatility;
const low = Math.min(open, close) - Math.random() * volatility;
const volume = 800000 + Math.random() * 1000000;
data.push({
timestamp: Date.now() - (length - i) * 3600000,
open, high, low, close, volume
});
price = close;
}
return data;
}
/**
* Generate divergence data
*/
generateDivergenceData() {
const data = [];
let price = 50000;
for (let i = 0; i < 100; i++) {
let close;
// Create divergence: price makes lower low, but momentum increases
if (i < 50) {
close = price - (i * 50); // Declining price
} else {
close = price - (50 * 50) + ((i - 50) * 30); // Price slightly recovering
}
const volatility = Math.abs(close) * 0.01;
const open = price;
const high = Math.max(open, close) + volatility;
const low = Math.min(open, close) - volatility;
const volume = 500000 + Math.random() * 500000;
data.push({
timestamp: Date.now() - (100 - i) * 3600000,
open, high, low, close, volume
});
price = close;
}
return data;
}
/**
* Validate OHLCV data
*/
isValidOHLCV(data) {
if (!data) return false;
const requiredFields = ['timestamp', 'open', 'high', 'low', 'close', 'volume'];
for (const field of requiredFields) {
if (!(field in data)) return false;
if (typeof data[field] !== 'number') return false;
if (field !== 'timestamp' && data[field] < 0) return false;
}
// High should be highest, low should be lowest
if (data.high < data.low) return false;
if (data.high < data.open || data.high < data.close) return false;
if (data.low > data.open || data.low > data.close) return false;
return true;
}
}
/**
* Run tests when module is loaded
*/
export async function runTests() {
const tester = new TradingSystemTests();
return await tester.runAll();
}
export default TradingSystemTests;