feat: Add ML prediction overlay components for trading charts
Add complete implementation of ML overlay components: - MLPredictionOverlay: Renders ML price predictions as line overlay - SignalMarkers: Displays BUY/SELL signal markers on chart - ICTConceptsOverlay: Renders Order Blocks, FVG, and Liquidity zones - useMlOverlayData: Custom hook with TanStack Query for data fetching - mlOverlay.types.ts: Type definitions for all ML overlay data Features: - Uses lightweight-charts API for efficient rendering - Automatic caching with 60s stale time - Configurable colors and visibility - Clean up on component unmount - Full TypeScript support Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
261dc4c71c
commit
d3f4aa3385
91
src/hooks/charts/useMlOverlayData.ts
Normal file
91
src/hooks/charts/useMlOverlayData.ts
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/**
|
||||||
|
* useMlOverlayData Hook
|
||||||
|
* Custom hook for fetching and caching ML overlay data for trading charts
|
||||||
|
* Uses TanStack Query for efficient data fetching and caching
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import type {
|
||||||
|
MLPrediction,
|
||||||
|
SignalMarker,
|
||||||
|
ICTConcept,
|
||||||
|
MLPredictionResponse,
|
||||||
|
} from '../../types/mlOverlay.types';
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Constants
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
const ML_API_URL = import.meta.env.VITE_ML_URL || 'http://localhost:3083';
|
||||||
|
const STALE_TIME = 60000; // 60 seconds
|
||||||
|
const CACHE_TIME = 300000; // 5 minutes
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// API Functions
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
async function fetchMLPredictions(
|
||||||
|
symbol: string,
|
||||||
|
timeframe: string
|
||||||
|
): Promise<MLPredictionResponse> {
|
||||||
|
const response = await fetch(
|
||||||
|
`${ML_API_URL}/api/ml/predictions/${symbol}/${timeframe}`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Failed to fetch ML predictions: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Hook
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export interface UseMlOverlayDataOptions {
|
||||||
|
symbol: string;
|
||||||
|
timeframe: string;
|
||||||
|
enabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UseMlOverlayDataResult {
|
||||||
|
predictions: MLPrediction[];
|
||||||
|
signals: SignalMarker[];
|
||||||
|
ictConcepts: ICTConcept[];
|
||||||
|
isLoading: boolean;
|
||||||
|
error: Error | null;
|
||||||
|
refetch: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useMlOverlayData({
|
||||||
|
symbol,
|
||||||
|
timeframe,
|
||||||
|
enabled = true,
|
||||||
|
}: UseMlOverlayDataOptions): UseMlOverlayDataResult {
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
isLoading,
|
||||||
|
error,
|
||||||
|
refetch,
|
||||||
|
} = useQuery({
|
||||||
|
queryKey: ['ml-predictions', symbol, timeframe],
|
||||||
|
queryFn: () => fetchMLPredictions(symbol, timeframe),
|
||||||
|
staleTime: STALE_TIME,
|
||||||
|
gcTime: CACHE_TIME,
|
||||||
|
enabled,
|
||||||
|
retry: 2,
|
||||||
|
retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 10000),
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
predictions: data?.predictions || [],
|
||||||
|
signals: data?.signals || [],
|
||||||
|
ictConcepts: data?.ictConcepts || [],
|
||||||
|
isLoading,
|
||||||
|
error: error as Error | null,
|
||||||
|
refetch,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useMlOverlayData;
|
||||||
@ -0,0 +1,134 @@
|
|||||||
|
/**
|
||||||
|
* ICTConceptsOverlay Component
|
||||||
|
* Renders ICT concepts (Order Blocks, FVG, Liquidity) as rectangles on the chart
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { useEffect, useRef } from 'react';
|
||||||
|
import type { IChartApi, ISeriesApi, Time } from 'lightweight-charts';
|
||||||
|
import type { ICTConcept } from '../../../../../types/mlOverlay.types';
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Types
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export interface ICTConceptsOverlayProps {
|
||||||
|
chartRef: React.RefObject<IChartApi>;
|
||||||
|
ictConcepts: ICTConcept[];
|
||||||
|
visible?: boolean;
|
||||||
|
colors?: {
|
||||||
|
OrderBlock: string;
|
||||||
|
FVG: string;
|
||||||
|
Liquidity: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RectangleData {
|
||||||
|
time: Time;
|
||||||
|
value: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Default Colors
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
const DEFAULT_COLORS = {
|
||||||
|
OrderBlock: 'rgba(59, 130, 246, 0.3)', // Blue
|
||||||
|
FVG: 'rgba(251, 191, 36, 0.3)', // Yellow
|
||||||
|
Liquidity: 'rgba(249, 115, 22, 0.3)', // Orange
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Component
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export const ICTConceptsOverlay: React.FC<ICTConceptsOverlayProps> = ({
|
||||||
|
chartRef,
|
||||||
|
ictConcepts,
|
||||||
|
visible = true,
|
||||||
|
colors = DEFAULT_COLORS,
|
||||||
|
}) => {
|
||||||
|
const conceptSeriesRef = useRef<Map<string, ISeriesApi<'Area'>>>(new Map());
|
||||||
|
|
||||||
|
// Initialize series for each ICT concept
|
||||||
|
useEffect(() => {
|
||||||
|
if (!chartRef.current || !visible) return;
|
||||||
|
|
||||||
|
const chart = chartRef.current;
|
||||||
|
const seriesMap = new Map<string, ISeriesApi<'Area'>>();
|
||||||
|
|
||||||
|
// Create series for each concept type
|
||||||
|
ictConcepts.forEach((concept, index) => {
|
||||||
|
const conceptId = `${concept.type}-${index}`;
|
||||||
|
|
||||||
|
if (!conceptSeriesRef.current.has(conceptId)) {
|
||||||
|
const color = colors[concept.type] || DEFAULT_COLORS[concept.type];
|
||||||
|
|
||||||
|
const series = chart.addAreaSeries({
|
||||||
|
topColor: color,
|
||||||
|
bottomColor: color,
|
||||||
|
lineColor: color.replace('0.3', '0.8'),
|
||||||
|
lineWidth: 1,
|
||||||
|
crosshairMarkerVisible: false,
|
||||||
|
lastValueVisible: false,
|
||||||
|
priceLineVisible: false,
|
||||||
|
title: `${concept.type}`,
|
||||||
|
});
|
||||||
|
|
||||||
|
seriesMap.set(conceptId, series);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
conceptSeriesRef.current = seriesMap;
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
// Cleanup: remove all series
|
||||||
|
conceptSeriesRef.current.forEach((series) => {
|
||||||
|
chart.removeSeries(series);
|
||||||
|
});
|
||||||
|
conceptSeriesRef.current.clear();
|
||||||
|
};
|
||||||
|
}, [chartRef, ictConcepts, ictConcepts.length, visible, colors]);
|
||||||
|
|
||||||
|
// Update concept data
|
||||||
|
useEffect(() => {
|
||||||
|
if (!chartRef.current || !visible || ictConcepts.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ictConcepts.forEach((concept, index) => {
|
||||||
|
const conceptId = `${concept.type}-${index}`;
|
||||||
|
const series = conceptSeriesRef.current.get(conceptId);
|
||||||
|
|
||||||
|
if (!series) return;
|
||||||
|
|
||||||
|
// Create rectangle data
|
||||||
|
const timeStart = (concept.timeStart / 1000) as Time;
|
||||||
|
const timeEnd = (concept.timeEnd / 1000) as Time;
|
||||||
|
|
||||||
|
const rectangleData: RectangleData[] = [
|
||||||
|
{ time: timeStart, value: concept.priceTop },
|
||||||
|
{ time: timeStart, value: concept.priceBottom },
|
||||||
|
{ time: timeEnd, value: concept.priceBottom },
|
||||||
|
{ time: timeEnd, value: concept.priceTop },
|
||||||
|
{ time: timeStart, value: concept.priceTop },
|
||||||
|
];
|
||||||
|
|
||||||
|
series.setData(rectangleData);
|
||||||
|
});
|
||||||
|
}, [chartRef, ictConcepts, visible]);
|
||||||
|
|
||||||
|
// Update visibility
|
||||||
|
useEffect(() => {
|
||||||
|
if (!chartRef.current) return;
|
||||||
|
|
||||||
|
conceptSeriesRef.current.forEach((series) => {
|
||||||
|
series.applyOptions({
|
||||||
|
visible,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, [chartRef, visible]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ICTConceptsOverlay;
|
||||||
@ -0,0 +1,95 @@
|
|||||||
|
/**
|
||||||
|
* MLPredictionOverlay Component
|
||||||
|
* Renders ML price predictions as a line overlay on the trading chart
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { useEffect, useRef } from 'react';
|
||||||
|
import type { IChartApi, ISeriesApi, LineData, Time } from 'lightweight-charts';
|
||||||
|
import type { MLPrediction } from '../../../../../types/mlOverlay.types';
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Types
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export interface MLPredictionOverlayProps {
|
||||||
|
chartRef: React.RefObject<IChartApi>;
|
||||||
|
predictions: MLPrediction[];
|
||||||
|
visible?: boolean;
|
||||||
|
lineColor?: string;
|
||||||
|
lineWidth?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Component
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export const MLPredictionOverlay: React.FC<MLPredictionOverlayProps> = ({
|
||||||
|
chartRef,
|
||||||
|
predictions,
|
||||||
|
visible = true,
|
||||||
|
lineColor = '#3b82f6',
|
||||||
|
lineWidth = 2,
|
||||||
|
}) => {
|
||||||
|
const predictionSeriesRef = useRef<ISeriesApi<'Line'> | null>(null);
|
||||||
|
|
||||||
|
// Initialize prediction line series
|
||||||
|
useEffect(() => {
|
||||||
|
if (!chartRef.current || !visible) return;
|
||||||
|
|
||||||
|
const chart = chartRef.current;
|
||||||
|
|
||||||
|
// Create line series for predictions
|
||||||
|
const predictionSeries = chart.addLineSeries({
|
||||||
|
color: lineColor,
|
||||||
|
lineWidth: lineWidth as 1 | 2 | 3 | 4,
|
||||||
|
lineStyle: 0,
|
||||||
|
crosshairMarkerVisible: true,
|
||||||
|
crosshairMarkerRadius: 6,
|
||||||
|
crosshairMarkerBorderColor: lineColor,
|
||||||
|
crosshairMarkerBackgroundColor: lineColor,
|
||||||
|
lastValueVisible: true,
|
||||||
|
priceLineVisible: true,
|
||||||
|
title: 'ML Prediction',
|
||||||
|
});
|
||||||
|
|
||||||
|
predictionSeriesRef.current = predictionSeries;
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (predictionSeriesRef.current) {
|
||||||
|
chart.removeSeries(predictionSeriesRef.current);
|
||||||
|
predictionSeriesRef.current = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [chartRef, visible, lineColor, lineWidth]);
|
||||||
|
|
||||||
|
// Update prediction data
|
||||||
|
useEffect(() => {
|
||||||
|
if (!predictionSeriesRef.current || !visible || predictions.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert predictions to line data
|
||||||
|
const lineData: LineData[] = predictions.map((pred) => ({
|
||||||
|
time: (pred.timestamp / 1000) as Time,
|
||||||
|
value: pred.price,
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Sort by time (required by lightweight-charts)
|
||||||
|
lineData.sort((a, b) => (a.time as number) - (b.time as number));
|
||||||
|
|
||||||
|
predictionSeriesRef.current.setData(lineData);
|
||||||
|
}, [predictions, visible]);
|
||||||
|
|
||||||
|
// Update visibility
|
||||||
|
useEffect(() => {
|
||||||
|
if (!predictionSeriesRef.current) return;
|
||||||
|
|
||||||
|
predictionSeriesRef.current.applyOptions({
|
||||||
|
visible,
|
||||||
|
});
|
||||||
|
}, [visible]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MLPredictionOverlay;
|
||||||
154
src/modules/trading/components/charts/overlays/README.md
Normal file
154
src/modules/trading/components/charts/overlays/README.md
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
# ML Chart Overlays
|
||||||
|
|
||||||
|
Componentes de React para visualizar predicciones ML en gráficos de trading usando lightweight-charts.
|
||||||
|
|
||||||
|
## Componentes
|
||||||
|
|
||||||
|
### 1. MLPredictionOverlay
|
||||||
|
Renderiza predicciones de precio ML como una línea sobre el gráfico.
|
||||||
|
|
||||||
|
**Props:**
|
||||||
|
- `chartRef`: Referencia al chart de lightweight-charts
|
||||||
|
- `predictions`: Array de predicciones ML
|
||||||
|
- `visible`: Mostrar/ocultar overlay (default: true)
|
||||||
|
- `lineColor`: Color de la línea (default: '#3b82f6')
|
||||||
|
- `lineWidth`: Grosor de línea (default: 2)
|
||||||
|
|
||||||
|
### 2. SignalMarkers
|
||||||
|
Renderiza marcadores de señales BUY/SELL en el gráfico.
|
||||||
|
|
||||||
|
**Props:**
|
||||||
|
- `chartRef`: Referencia al chart de lightweight-charts
|
||||||
|
- `candleSeriesRef`: Referencia a la serie de velas
|
||||||
|
- `signals`: Array de señales
|
||||||
|
- `visible`: Mostrar/ocultar markers (default: true)
|
||||||
|
|
||||||
|
### 3. ICTConceptsOverlay
|
||||||
|
Renderiza conceptos ICT (Order Blocks, FVG, Liquidity) como rectángulos.
|
||||||
|
|
||||||
|
**Props:**
|
||||||
|
- `chartRef`: Referencia al chart de lightweight-charts
|
||||||
|
- `ictConcepts`: Array de conceptos ICT
|
||||||
|
- `visible`: Mostrar/ocultar overlay (default: true)
|
||||||
|
- `colors`: Objeto con colores por tipo de concepto
|
||||||
|
|
||||||
|
## Hook
|
||||||
|
|
||||||
|
### useMlOverlayData
|
||||||
|
Hook personalizado para obtener datos ML desde el backend con caché automático.
|
||||||
|
|
||||||
|
**Opciones:**
|
||||||
|
- `symbol`: Símbolo del activo (ej: 'EURUSD')
|
||||||
|
- `timeframe`: Temporalidad (ej: '1h', '4h')
|
||||||
|
- `enabled`: Activar/desactivar fetch (default: true)
|
||||||
|
|
||||||
|
**Retorna:**
|
||||||
|
- `predictions`: Array de predicciones
|
||||||
|
- `signals`: Array de señales
|
||||||
|
- `ictConcepts`: Array de conceptos ICT
|
||||||
|
- `isLoading`: Estado de carga
|
||||||
|
- `error`: Error si existe
|
||||||
|
- `refetch`: Función para refetch manual
|
||||||
|
|
||||||
|
## Ejemplo de Uso
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { useRef } from 'react';
|
||||||
|
import { IChartApi, ISeriesApi } from 'lightweight-charts';
|
||||||
|
import { useMlOverlayData } from '@/hooks/charts/useMlOverlayData';
|
||||||
|
import {
|
||||||
|
MLPredictionOverlay,
|
||||||
|
SignalMarkers,
|
||||||
|
ICTConceptsOverlay,
|
||||||
|
} from '@/modules/trading/components/charts/overlays';
|
||||||
|
|
||||||
|
function TradingChart() {
|
||||||
|
const chartRef = useRef<IChartApi>(null);
|
||||||
|
const candleSeriesRef = useRef<ISeriesApi<'Candlestick'>>(null);
|
||||||
|
|
||||||
|
const { predictions, signals, ictConcepts, isLoading } = useMlOverlayData({
|
||||||
|
symbol: 'EURUSD',
|
||||||
|
timeframe: '1h',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isLoading) return <div>Loading...</div>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{/* Tu componente de chart aquí */}
|
||||||
|
|
||||||
|
<MLPredictionOverlay
|
||||||
|
chartRef={chartRef}
|
||||||
|
predictions={predictions}
|
||||||
|
visible={true}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SignalMarkers
|
||||||
|
chartRef={chartRef}
|
||||||
|
candleSeriesRef={candleSeriesRef}
|
||||||
|
signals={signals}
|
||||||
|
visible={true}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ICTConceptsOverlay
|
||||||
|
chartRef={chartRef}
|
||||||
|
ictConcepts={ictConcepts}
|
||||||
|
visible={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Backend
|
||||||
|
|
||||||
|
Los componentes esperan que el backend exponga el siguiente endpoint:
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /api/ml/predictions/:symbol/:timeframe
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"symbol": "EURUSD",
|
||||||
|
"timeframe": "1h",
|
||||||
|
"predictions": [
|
||||||
|
{
|
||||||
|
"timestamp": 1706400000000,
|
||||||
|
"price": 1.0850,
|
||||||
|
"confidence": 0.85,
|
||||||
|
"type": "buy"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"signals": [
|
||||||
|
{
|
||||||
|
"time": 1706400000000,
|
||||||
|
"position": "belowBar",
|
||||||
|
"color": "#10b981",
|
||||||
|
"text": "BUY",
|
||||||
|
"shape": "arrowUp"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ictConcepts": [
|
||||||
|
{
|
||||||
|
"type": "OrderBlock",
|
||||||
|
"timeStart": 1706400000000,
|
||||||
|
"timeEnd": 1706403600000,
|
||||||
|
"priceTop": 1.0860,
|
||||||
|
"priceBottom": 1.0840
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"generatedAt": "2026-01-28T10:00:00Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notas
|
||||||
|
|
||||||
|
- Los componentes usan TanStack Query para caché automático (60s stale time)
|
||||||
|
- Las timestamps deben estar en milisegundos
|
||||||
|
- Los overlays se limpian automáticamente al desmontar
|
||||||
|
- Los colores predeterminados son:
|
||||||
|
- OrderBlock: Azul (#3b82f6)
|
||||||
|
- FVG: Amarillo (#fbbf24)
|
||||||
|
- Liquidity: Naranja (#f97316)
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
/**
|
||||||
|
* SignalMarkers Component
|
||||||
|
* Renders buy/sell signal markers on the trading chart
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { useEffect, useRef } from 'react';
|
||||||
|
import type { IChartApi, ISeriesApi, Time, SeriesMarker } from 'lightweight-charts';
|
||||||
|
import type { SignalMarker } from '../../../../../types/mlOverlay.types';
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Types
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export interface SignalMarkersProps {
|
||||||
|
chartRef: React.RefObject<IChartApi>;
|
||||||
|
candleSeriesRef: React.RefObject<ISeriesApi<'Candlestick'>>;
|
||||||
|
signals: SignalMarker[];
|
||||||
|
visible?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Helper Functions
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
function convertToLightweightMarkers(signals: SignalMarker[]): SeriesMarker<Time>[] {
|
||||||
|
return signals.map((signal) => ({
|
||||||
|
time: (signal.time / 1000) as Time,
|
||||||
|
position: signal.position,
|
||||||
|
color: signal.color,
|
||||||
|
shape: signal.shape,
|
||||||
|
text: signal.text,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Component
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export const SignalMarkers: React.FC<SignalMarkersProps> = ({
|
||||||
|
chartRef,
|
||||||
|
candleSeriesRef,
|
||||||
|
signals,
|
||||||
|
visible = true,
|
||||||
|
}) => {
|
||||||
|
const markersSetRef = useRef(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!chartRef.current || !candleSeriesRef.current || !visible || signals.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const candleSeries = candleSeriesRef.current;
|
||||||
|
|
||||||
|
// Convert and set markers
|
||||||
|
const markers = convertToLightweightMarkers(signals);
|
||||||
|
candleSeries.setMarkers(markers);
|
||||||
|
markersSetRef.current = true;
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
// Clear markers on cleanup
|
||||||
|
if (markersSetRef.current && candleSeriesRef.current) {
|
||||||
|
candleSeriesRef.current.setMarkers([]);
|
||||||
|
markersSetRef.current = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [chartRef, candleSeriesRef, signals, visible]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SignalMarkers;
|
||||||
13
src/modules/trading/components/charts/overlays/index.ts
Normal file
13
src/modules/trading/components/charts/overlays/index.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* Chart Overlays - Barrel Export
|
||||||
|
* Exports all ML chart overlay components
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { MLPredictionOverlay } from './MLPredictionOverlay';
|
||||||
|
export type { MLPredictionOverlayProps } from './MLPredictionOverlay';
|
||||||
|
|
||||||
|
export { SignalMarkers } from './SignalMarkers';
|
||||||
|
export type { SignalMarkersProps } from './SignalMarkers';
|
||||||
|
|
||||||
|
export { ICTConceptsOverlay } from './ICTConceptsOverlay';
|
||||||
|
export type { ICTConceptsOverlayProps } from './ICTConceptsOverlay';
|
||||||
106
src/types/mlOverlay.types.ts
Normal file
106
src/types/mlOverlay.types.ts
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/**
|
||||||
|
* ML Overlay Types
|
||||||
|
* Type definitions for ML predictions overlays on trading charts
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// ML Prediction Types
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export type PredictionType = 'buy' | 'sell' | 'neutral';
|
||||||
|
|
||||||
|
export interface MLPrediction {
|
||||||
|
timestamp: number;
|
||||||
|
price: number;
|
||||||
|
confidence: number;
|
||||||
|
type: PredictionType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Signal Marker Types
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export type MarkerPosition = 'aboveBar' | 'belowBar';
|
||||||
|
export type MarkerShape = 'arrowUp' | 'arrowDown' | 'circle';
|
||||||
|
|
||||||
|
export interface SignalMarker {
|
||||||
|
time: number;
|
||||||
|
position: MarkerPosition;
|
||||||
|
color: string;
|
||||||
|
text: string;
|
||||||
|
shape: MarkerShape;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// ICT Concept Types
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export type ICTConceptType = 'OrderBlock' | 'FVG' | 'Liquidity';
|
||||||
|
|
||||||
|
export interface ICTConcept {
|
||||||
|
type: ICTConceptType;
|
||||||
|
timeStart: number;
|
||||||
|
timeEnd: number;
|
||||||
|
priceTop: number;
|
||||||
|
priceBottom: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Overlay Configuration Types
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export interface MLOverlayConfig {
|
||||||
|
showPredictions: boolean;
|
||||||
|
showSignals: boolean;
|
||||||
|
showICTConcepts: boolean;
|
||||||
|
predictionLineColor: string;
|
||||||
|
predictionLineWidth: number;
|
||||||
|
signalColors: {
|
||||||
|
buy: string;
|
||||||
|
sell: string;
|
||||||
|
};
|
||||||
|
ictColors: {
|
||||||
|
OrderBlock: string;
|
||||||
|
FVG: string;
|
||||||
|
Liquidity: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DEFAULT_OVERLAY_CONFIG: MLOverlayConfig = {
|
||||||
|
showPredictions: true,
|
||||||
|
showSignals: true,
|
||||||
|
showICTConcepts: true,
|
||||||
|
predictionLineColor: '#3b82f6',
|
||||||
|
predictionLineWidth: 2,
|
||||||
|
signalColors: {
|
||||||
|
buy: '#10b981',
|
||||||
|
sell: '#ef4444',
|
||||||
|
},
|
||||||
|
ictColors: {
|
||||||
|
OrderBlock: '#3b82f6',
|
||||||
|
FVG: '#fbbf24',
|
||||||
|
Liquidity: '#f97316',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// API Response Types
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export interface MLPredictionResponse {
|
||||||
|
symbol: string;
|
||||||
|
timeframe: string;
|
||||||
|
predictions: MLPrediction[];
|
||||||
|
signals: SignalMarker[];
|
||||||
|
ictConcepts: ICTConcept[];
|
||||||
|
generatedAt: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MLOverlayData {
|
||||||
|
predictions: MLPrediction[];
|
||||||
|
signals: SignalMarker[];
|
||||||
|
ictConcepts: ICTConcept[];
|
||||||
|
isLoading: boolean;
|
||||||
|
error: string | null;
|
||||||
|
lastUpdated: string | null;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user