SoftTraderFrontend/components/candlestick-chart/mockCandles.ts
2026-03-20 11:10:13 -04:00

112 lines
3.6 KiB
TypeScript

import type { Candle } from './chartTypes';
/**
* Generates realistic mock candlestick data for development/testing.
* The data simulates price movements with trends, volatility, and volume patterns.
*/
export function generateMockCandles(
symbol: string,
timeframe: string,
barSize: string,
count: number = 200
): Candle[] {
// Base price varies by symbol for realistic appearance
const symbolHash = symbol.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0);
let basePrice = 100 + (symbolHash % 900); // Price between 100-1000
// Timeframe affects interval between candles
const intervalMs = getIntervalMs(barSize);
// Start from a past time
const now = Date.now();
const startTime = now - (count * intervalMs);
const candles: Candle[] = [];
let currentPrice = basePrice;
let trend = 0; // -1 to 1, represents current trend direction
let volatility = 0.02; // 2% base volatility
for (let i = 0; i < count; i++) {
// Slowly drift the trend
trend += (Math.random() - 0.5) * 0.1;
trend = Math.max(-1, Math.min(1, trend)); // Clamp trend
// Occasionally spike volatility
if (Math.random() < 0.05) {
volatility = 0.02 + Math.random() * 0.03;
} else {
volatility = volatility * 0.95 + 0.02 * 0.05; // Decay back to base
}
// Calculate price movement
const trendComponent = trend * volatility * currentPrice * 0.5;
const randomComponent = (Math.random() - 0.5) * volatility * currentPrice;
const priceChange = trendComponent + randomComponent;
// Generate OHLC
const open = currentPrice;
const close = currentPrice + priceChange;
// High and low extend beyond open/close
const range = Math.abs(close - open);
const wickExtension = range * (0.3 + Math.random() * 0.7);
const high = Math.max(open, close) + wickExtension * Math.random();
const low = Math.min(open, close) - wickExtension * Math.random();
// Volume correlates with price movement
const baseVolume = 1000000 + symbolHash * 1000;
const volumeMultiplier = 0.5 + Math.abs(priceChange / currentPrice) * 10 + Math.random();
const volume = Math.floor(baseVolume * volumeMultiplier);
candles.push({
time: startTime + i * intervalMs,
open: roundPrice(open),
high: roundPrice(high),
low: roundPrice(low),
close: roundPrice(close),
volume,
});
currentPrice = close;
}
return candles;
}
function getIntervalMs(barSize: string): number {
const intervals: Record<string, number> = {
'1m': 60 * 1000,
'5m': 5 * 60 * 1000,
'15m': 15 * 60 * 1000,
'30m': 30 * 60 * 1000,
'1h': 60 * 60 * 1000,
'4h': 4 * 60 * 60 * 1000,
'1d': 24 * 60 * 60 * 1000,
'1w': 7 * 24 * 60 * 60 * 1000,
};
return intervals[barSize] || intervals['1h'];
}
function roundPrice(price: number): number {
// Round to 2 decimal places
return Math.round(price * 100) / 100;
}
/**
* Simulates an async API fetch with realistic delay.
* TODO: Replace with real API integration.
*/
export async function fetchMockCandles(
symbol: string,
user: string,
timeframe: string,
barSize: string
): Promise<Candle[]> {
// Simulate network delay
await new Promise(resolve => setTimeout(resolve, 300 + Math.random() * 200));
// Generate candles (user param would be used for personalized data in real API)
console.log(`[v0] Fetching candles for ${symbol} (user: ${user}, timeframe: ${timeframe}, barSize: ${barSize})`);
return generateMockCandles(symbol, timeframe, barSize, 200);
}