import { Component, OnInit, inject } from '@angular/core'; import { CommonModule } from '@angular/common'; import { MatCardModule } from '@angular/material/card'; import { Location } from '@angular/common'; import { NgApexchartsModule } from 'ng-apexcharts'; import { ChartService } from './chart.service'; import { MatPaginatorModule } from '@angular/material/paginator'; import { PageEvent } from '@angular/material/paginator'; import { MatSlideToggleModule } from '@angular/material/slide-toggle'; @Component({ selector: 'app-analysispage', standalone: true, imports: [CommonModule, MatSlideToggleModule, MatCardModule, MatPaginatorModule, NgApexchartsModule], templateUrl: './analysispage.html', styleUrls: ['./analysispage.scss'] }) export class Analysispage implements OnInit { originalOrder = (): number => 0; private location = inject(Location); result: any; pageIndex = 0; pageSize = 5; sort: { key: 'combined_overall_score' | 'overall_ta_score' | 'overall_fa_score' | 'news_overall_score', direction: 'asc' | 'desc' } = { key: 'combined_overall_score', direction: 'desc' }; closeAreaOptions: any; candlestickChartOptions: any; overallChart: any; strategyChart: any; strategyChartIndex: number = 0; predictedChart: any; highLowChartOptions: any; selectedIndicator: any = 'RSI'; selectedStrategy: any = 'RSI 14'; activeCompany: number = 0; isCandlestick = true; constructor(private chartService: ChartService) { } ngOnInit(): void { const s = this.location.getState() as { result?: unknown } | null; this.result = s?.result ?? null; const validData = this.result.filter((item: any) => !item.error); const invalidData = this.result.filter((item: any) => item.error); validData.sort((a: any, b: any) => b.combined_overall_score - a.combined_overall_score); this.result = [...validData, ...invalidData]; console.log('Analysis result:', this.result); this.loadCharts(); this.loadPredictedCharts(); this.loadStrategiesChart('RSI 14'); } // Map a row to the numeric value for a given sort key private sortValue(row: any, key: typeof this.sort.key): number { switch (key) { case 'combined_overall_score': return Number(row?.combined_overall_score ?? -Infinity); case 'overall_ta_score': return Number(row?.overall_ta_score ?? -Infinity); case 'overall_fa_score': return Number(row?.fundamental_analysis?.overall_fa_score ?? -Infinity); case 'news_overall_score': return Number(row?.news_overall_score ?? -Infinity); } } // Sorted list (used by the paginator slice) get sortedResults(): any[] { if (!Array.isArray(this.result)) return []; const arr = [...this.result]; arr.sort((a, b) => { const av = this.sortValue(a, this.sort.key); const bv = this.sortValue(b, this.sort.key); return this.sort.direction === 'asc' ? av - bv : bv - av; }); return arr; } // Page slice over the sorted list get pagedResults(): any[] { const start = this.pageIndex * this.pageSize; return this.sortedResults.slice(start, start + this.pageSize); } // Toggle sort on header click toggleSort(key: typeof this.sort.key) { if (this.sort.key === key) { this.sort.direction = this.sort.direction === 'asc' ? 'desc' : 'asc'; } else { this.sort.key = key; this.sort.direction = 'desc'; // default direction on new column } this.pageIndex = 0; // reset to first page on sort change } // paginator change onPage(e: PageEvent) { this.pageIndex = e.pageIndex; this.pageSize = e.pageSize; } showStrategies(selectedIndicator: any) { this.selectedIndicator = selectedIndicator; const strategies = this.result[this.activeCompany][selectedIndicator]; const firstStrategyKey = Object.keys(strategies)[0]; if (firstStrategyKey) { this.selectedStrategy = firstStrategyKey; this.loadStrategiesChart(firstStrategyKey); } } loadStrategiesChart(strategyName: any) { this.strategyChartIndex = 0; this.selectedStrategy = strategyName; this.strategyChart = this.chartService.getChartOptions(strategyName, this.result[this.activeCompany]); console.log(this.strategyChart); } getClass(signal: any) { if (typeof signal === 'string') { switch (signal.toLowerCase()) { case 'buy': case 'good': case 'positive': case 'bullish': return 'green'; case 'dbuy': case 'bad': case 'negative': case 'bearish': return 'red'; case 'neutral': case 'none': return 'yellow'; default: return ''; } } else { return 'strategyvalue' } } loadCharts() { // close price chart const data = this.result[this.activeCompany]['ohlc_data'] as Array<{ x: string; y: [number, number, number, number] }>; // Optional: keep sorted and remove duplicate dates const closeSeries = [...data] .sort((a, b) => a.x.localeCompare(b.x)) .filter((d, i, arr) => i === 0 || d.x !== arr[i - 1].x) .map(d => ({ x: d.x, y: d.y[3] })); // close = index 3 this.closeAreaOptions = { chart: { type: 'area', height: 400, width: 1200 }, series: [ { name: 'Close', data: closeSeries // [{x: '2025-08-01', y: 2350.9}, ...] } ], xaxis: { type: 'category', labels: { style: { colors: '#ffffff' } } }, yaxis: { opposite: true, labels: { style: { colors: '#ffffff' } } }, tooltip: { theme: 'dark' } }; //candlestick chart this.candlestickChartOptions = { chart: { type: 'candlestick', height: 400, width: 1200 }, series: [{ name: this.activeCompany, data }], // x can be a plain string when type='category' xaxis: { type: 'category', labels: { style: { colors: '#ffffff' } } }, yaxis: { opposite: true, labels: { style: { colors: '#ffffff' } } }, tooltip: { theme: 'dark' } }; } loadPredictedCharts() { //donut chart this.overallChart = { series: [ this.result[this.activeCompany].overall_ta_score, this.result[this.activeCompany].overall_fa_score, this.result[this.activeCompany].news_overall_score ], // Three values for the donut chart chart: { type: 'donut', width: 500 }, labels: ['TA', 'FA', 'News'], // Set the labels to show on the chart plotOptions: { pie: { donut: { size: '60%', // Control the thickness of the donut labels: { show: true, name: { show: false }, value: { show: true, // Show values inside the donut chart fontSize: '16px', // Font size for values color: 'white' // White color for the values }, total: { show: true, label: 'Total', // Label at the center formatter: (w: any) => { // Display the total value (sum of all slices) return w.globals.seriesTotals.reduce((a: any, b: any) => a + b, 0) + '%'; } } } } } }, fill: { type: 'solid', colors: ['#ff5733', '#33ff57', '#ffcc00'] // Colors for TA, FA, and News }, tooltip: { enabled: true, // Enable tooltips for the chart fillSeriesColor: false, theme: 'dark', style: { fontSize: '14px', color: 'white' // White text color for tooltips } }, legend: { show: true, position: 'bottom', // Position the legend at the bottom labels: { useSeriesColors: true, // Use the series colors for legend colors: ['white'] // White text color for legend } } }; // Predicted High/Low 15-day chart (single chart with two series) const highsRaw = this.result[this.activeCompany].ai_predicted_daily_high_15 ?? []; const lowsRaw = this.result[this.activeCompany].ai_predicted_daily_low_15 ?? []; const dates15 = this.result[this.activeCompany].ai_predicted_dates_15 ?? []; const highs = highsRaw.map((v: any) => Number(Number(v).toFixed(2))); const lows = lowsRaw.map((v: any) => Number(Number(v).toFixed(2))); if (highs.length && lows.length && dates15.length && highs.length === lows.length && highs.length === dates15.length) { this.highLowChartOptions = { chart: { type: 'line', height: 400, width: 1500, toolbar: { show: false } }, series: [ { name: 'Predicted High', data: highs, color: '#22C55E' }, // green { name: 'Predicted Low', data: lows, color: '#EF4444' } // red ], stroke: { width: 2, curve: 'smooth' }, markers: { size: 3 }, xaxis: { categories: dates15, type: 'category', tickPlacement: 'on', labels: { rotate: -45, rotateAlways: true, hideOverlappingLabels: false, trim: false, minHeight: 70, style: { colors: '#ffffff', fontSize: '12px' } } }, yaxis: { opposite: true, labels: { style: { colors: '#ffffff' } } }, tooltip: { shared: true, intersect: false, theme: 'dark', y: { formatter: (val: number) => (val != null ? val.toFixed(2) : '') } }, legend: { position: 'top', labels: { colors: '#ffffff', useSeriesColors: false } } }; } else { this.highLowChartOptions = null; } } selectCompany(index: number) { this.activeCompany = index; this.loadCharts(); this.loadPredictedCharts(); } onModeChange(checked: boolean) { this.isCandlestick = checked; this.loadCharts(); } previousChart(): void { if (this.strategyChartIndex > 0) { this.strategyChartIndex--; } } nextChart(): void { if (this.strategyChartIndex < this.strategyChart.length - 1) { this.strategyChartIndex++; } } }