feat: competitive intelligence & historical pattern matching layer
This commit is contained in:
@@ -26,6 +26,34 @@ export const mockPositions = [
|
||||
{ id: 'p1', broker_account_id: null, ticker: 'AAPL', quantity: 10, avg_entry_price: 185.50, current_price: 188.20, unrealized_pnl: 27.00, realized_pnl: 0, updated_at: '2026-04-11T12:00:00Z' },
|
||||
];
|
||||
|
||||
export const mockMacroEvents = [
|
||||
{ id: 'me1', event_types: ['trade_barrier', 'cost_increase'], severity: 'high', affected_regions: ['US', 'CN'], affected_sectors: ['Technology'], affected_commodities: ['semiconductors'], summary: 'US tariffs on Chinese semiconductors', key_facts: ['25% tariff', 'Effective in 30 days'], estimated_duration: 'medium_term', confidence: 0.85, source_document_id: 'd1', created_at: '2026-05-15T14:00:00Z' },
|
||||
];
|
||||
|
||||
export const mockMacroImpacts = [
|
||||
{ id: 'mi1', event_id: 'me1', company_id: '1', ticker: 'AAPL', macro_impact_score: 0.45, impact_direction: 'negative', contributing_factors: ['geographic_overlap:0.650'], confidence: 0.8, computed_at: '2026-05-15T14:00:00Z', legal_name: 'Apple Inc.', sector: 'Technology', event_summary: 'US tariffs on Chinese semiconductors', event_severity: 'high', event_types: ['trade_barrier'], affected_regions: ['US', 'CN'] },
|
||||
];
|
||||
|
||||
export const mockTrendProjection = {
|
||||
id: 'tp1', trend_window_id: 't1', projected_direction: 'bearish', projected_strength: 0.6, projected_confidence: 0.5, projection_horizon: '7d', driving_factors: ['Macro signals project bearish impact'], macro_contribution_pct: 0.3, diverges_from_current: true, computed_at: '2026-05-15T14:00:00Z',
|
||||
};
|
||||
|
||||
export const mockCompetitors = [
|
||||
{ id: 'cr1', company_a_id: '1', company_b_id: '2', relationship_type: 'direct_rival', strength: 0.85, bidirectional: true, source: 'manual', active: true, created_at: '2026-04-01T00:00:00Z', updated_at: '2026-04-01T00:00:00Z', ticker: 'MSFT', legal_name: 'Microsoft Corporation' },
|
||||
];
|
||||
|
||||
export const mockHistoricalPatterns = [
|
||||
{ source_ticker: 'AAPL', target_ticker: 'AAPL', catalyst_type: 'earnings', time_horizon: '7d', sample_count: 12, bullish_pct: 0.75, bearish_pct: 0.25, avg_strength: 0.6, avg_time_to_resolution: 3.5, pattern_confidence: 0.72, data_start: '2025-01-01T00:00:00Z', data_end: '2026-04-01T00:00:00Z', tier: 'routine_signal', insufficient_data: false },
|
||||
];
|
||||
|
||||
export const mockCompetitiveSignals = [
|
||||
{ id: 'cs1', source_document_id: 'd1', source_ticker: 'MSFT', target_ticker: 'AAPL', catalyst_type: 'product_launch', pattern_confidence: 0.65, signal_direction: 'bearish', signal_strength: 0.4, relationship_strength: 0.85, computed_at: '2026-04-10T15:00:00Z' },
|
||||
];
|
||||
|
||||
export const mockCorporateDecisions = [
|
||||
{ catalyst_type: 'm_and_a', date: '2026-03-15T00:00:00Z', summary: 'Acquisition of AI startup for $2B', trend_direction: 'bullish', trend_strength: 0.7, sample_count: 5, pattern_confidence: 0.68, document_id: 'd1' },
|
||||
];
|
||||
|
||||
export const handlers = [
|
||||
// Query API (proxied at /api/)
|
||||
http.get('/api/companies', () => HttpResponse.json(mockCompanies)),
|
||||
@@ -69,4 +97,30 @@ export const handlers = [
|
||||
|
||||
// Health
|
||||
http.get('/api/health', () => HttpResponse.json({ status: 'ok' })),
|
||||
|
||||
// Macro events and impacts
|
||||
http.get('/api/macro/events', () => HttpResponse.json(mockMacroEvents)),
|
||||
http.get('/api/macro/events/:id', ({ params }) => {
|
||||
const ev = mockMacroEvents.find((e) => e.id === params.id);
|
||||
return ev ? HttpResponse.json({ ...ev, model_provider: 'ollama', model_name: 'test-model', prompt_version: 'event-v1', schema_version: '1.0.0', affected_companies: mockMacroImpacts }) : new HttpResponse(null, { status: 404 });
|
||||
}),
|
||||
http.get('/api/macro/impacts/:ticker', () => HttpResponse.json(mockMacroImpacts)),
|
||||
http.get('/api/admin/macro/status', () => HttpResponse.json({ macro_enabled: true, source: 'default' })),
|
||||
http.put('/api/admin/macro/toggle', async ({ request }) => {
|
||||
const body = await request.json() as Record<string, unknown>;
|
||||
return HttpResponse.json({ macro_enabled: body.enabled, previous_enabled: true, toggled_by: body.operator ?? 'operator' });
|
||||
}),
|
||||
http.get('/api/trends/:id/projection', () => HttpResponse.json(mockTrendProjection)),
|
||||
|
||||
// Competitive intelligence endpoints
|
||||
http.get('/registry/companies/:id/competitors', () => HttpResponse.json(mockCompetitors)),
|
||||
http.post('/registry/companies/:id/competitors/infer', () => HttpResponse.json(mockCompetitors)),
|
||||
http.get('/api/patterns/:ticker', () => HttpResponse.json(mockHistoricalPatterns)),
|
||||
http.get('/api/patterns/:ticker/competitive-signals', () => HttpResponse.json(mockCompetitiveSignals)),
|
||||
http.get('/api/patterns/:ticker/decisions', () => HttpResponse.json(mockCorporateDecisions)),
|
||||
http.get('/api/admin/competitive/status', () => HttpResponse.json({ enabled: true, toggled_at: '2026-05-15T14:00:00Z', toggled_by: 'operator' })),
|
||||
http.put('/api/admin/competitive/toggle', async ({ request }) => {
|
||||
const body = await request.json() as Record<string, unknown>;
|
||||
return HttpResponse.json({ enabled: body.enabled, previous_enabled: true, toggled_by: 'operator' });
|
||||
}),
|
||||
];
|
||||
|
||||
@@ -152,3 +152,19 @@ describe('Watchlists page', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Global Events page', () => {
|
||||
it('renders global events list with severity filter', async () => {
|
||||
renderRoute('/macro/events');
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Global Events')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders event summary from mock data', async () => {
|
||||
renderRoute('/macro/events');
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(/US tariffs on Chinese semiconductors/)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user