goldenChat base source add
This commit is contained in:
@@ -0,0 +1,242 @@
|
||||
/**
|
||||
* 보조지표 계산 Web Worker
|
||||
* - 메인 스레드를 차단하지 않고 지표 계산
|
||||
* - 복잡한 계산(MA, RSI, MACD 등)을 백그라운드에서 처리
|
||||
*/
|
||||
|
||||
self.addEventListener('message', (event) => {
|
||||
const { type, data } = event.data;
|
||||
|
||||
try {
|
||||
switch (type) {
|
||||
case 'CALCULATE_MA':
|
||||
const maResult = calculateMA(data.candles, data.periods);
|
||||
self.postMessage({ type: 'MA_RESULT', data: maResult });
|
||||
break;
|
||||
|
||||
case 'CALCULATE_RSI':
|
||||
const rsiResult = calculateRSI(data.candles, data.period);
|
||||
self.postMessage({ type: 'RSI_RESULT', data: rsiResult });
|
||||
break;
|
||||
|
||||
case 'CALCULATE_MACD':
|
||||
const macdResult = calculateMACD(data.candles, data.fastPeriod, data.slowPeriod, data.signalPeriod);
|
||||
self.postMessage({ type: 'MACD_RESULT', data: macdResult });
|
||||
break;
|
||||
|
||||
case 'CALCULATE_STOCHASTIC':
|
||||
const stochResult = calculateStochastic(data.candles, data.kPeriod, data.dPeriod);
|
||||
self.postMessage({ type: 'STOCHASTIC_RESULT', data: stochResult });
|
||||
break;
|
||||
|
||||
case 'CALCULATE_ALL':
|
||||
const allResults = calculateAllIndicators(data.candles, data.config);
|
||||
self.postMessage({ type: 'ALL_RESULT', data: allResults });
|
||||
break;
|
||||
|
||||
default:
|
||||
self.postMessage({ type: 'ERROR', error: 'Unknown command' });
|
||||
}
|
||||
} catch (error) {
|
||||
self.postMessage({ type: 'ERROR', error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 이동평균선 계산
|
||||
*/
|
||||
function calculateMA(candles, periods) {
|
||||
const results = {};
|
||||
|
||||
periods.forEach(period => {
|
||||
const ma = [];
|
||||
for (let i = 0; i < candles.length; i++) {
|
||||
if (i < period - 1) {
|
||||
ma.push(null);
|
||||
} else {
|
||||
let sum = 0;
|
||||
for (let j = 0; j < period; j++) {
|
||||
sum += candles[i - j].close;
|
||||
}
|
||||
ma.push(sum / period);
|
||||
}
|
||||
}
|
||||
results[`ma${period}`] = ma;
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* RSI 계산
|
||||
*/
|
||||
function calculateRSI(candles, period = 14) {
|
||||
const rsi = [];
|
||||
const gains = [];
|
||||
const losses = [];
|
||||
|
||||
for (let i = 0; i < candles.length; i++) {
|
||||
if (i === 0) {
|
||||
rsi.push(null);
|
||||
continue;
|
||||
}
|
||||
|
||||
const change = candles[i].close - candles[i - 1].close;
|
||||
gains.push(change > 0 ? change : 0);
|
||||
losses.push(change < 0 ? Math.abs(change) : 0);
|
||||
|
||||
if (i < period) {
|
||||
rsi.push(null);
|
||||
continue;
|
||||
}
|
||||
|
||||
const avgGain = gains.slice(-period).reduce((a, b) => a + b, 0) / period;
|
||||
const avgLoss = losses.slice(-period).reduce((a, b) => a + b, 0) / period;
|
||||
|
||||
if (avgLoss === 0) {
|
||||
rsi.push(100);
|
||||
} else {
|
||||
const rs = avgGain / avgLoss;
|
||||
rsi.push(100 - (100 / (1 + rs)));
|
||||
}
|
||||
}
|
||||
|
||||
return rsi;
|
||||
}
|
||||
|
||||
/**
|
||||
* MACD 계산
|
||||
*/
|
||||
function calculateMACD(candles, fastPeriod = 12, slowPeriod = 26, signalPeriod = 9) {
|
||||
// EMA 계산 헬퍼
|
||||
const calculateEMA = (values, period) => {
|
||||
const ema = [];
|
||||
const multiplier = 2 / (period + 1);
|
||||
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
if (i < period - 1) {
|
||||
ema.push(null);
|
||||
} else if (i === period - 1) {
|
||||
const sum = values.slice(0, period).reduce((a, b) => a + b, 0);
|
||||
ema.push(sum / period);
|
||||
} else {
|
||||
const value = (values[i] - ema[i - 1]) * multiplier + ema[i - 1];
|
||||
ema.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
return ema;
|
||||
};
|
||||
|
||||
const closes = candles.map(c => c.close);
|
||||
const fastEMA = calculateEMA(closes, fastPeriod);
|
||||
const slowEMA = calculateEMA(closes, slowPeriod);
|
||||
|
||||
const macdLine = [];
|
||||
for (let i = 0; i < candles.length; i++) {
|
||||
if (fastEMA[i] === null || slowEMA[i] === null) {
|
||||
macdLine.push(null);
|
||||
} else {
|
||||
macdLine.push(fastEMA[i] - slowEMA[i]);
|
||||
}
|
||||
}
|
||||
|
||||
const signalLine = calculateEMA(
|
||||
macdLine.map(v => v === null ? 0 : v),
|
||||
signalPeriod
|
||||
);
|
||||
|
||||
const histogram = [];
|
||||
for (let i = 0; i < candles.length; i++) {
|
||||
if (macdLine[i] === null || signalLine[i] === null) {
|
||||
histogram.push(null);
|
||||
} else {
|
||||
histogram.push(macdLine[i] - signalLine[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return { macdLine, signalLine, histogram };
|
||||
}
|
||||
|
||||
/**
|
||||
* Stochastic 계산
|
||||
*/
|
||||
function calculateStochastic(candles, kPeriod = 14, dPeriod = 3) {
|
||||
const stochK = [];
|
||||
|
||||
for (let i = 0; i < candles.length; i++) {
|
||||
if (i < kPeriod - 1) {
|
||||
stochK.push(null);
|
||||
continue;
|
||||
}
|
||||
|
||||
const slice = candles.slice(i - kPeriod + 1, i + 1);
|
||||
const highest = Math.max(...slice.map(c => c.high));
|
||||
const lowest = Math.min(...slice.map(c => c.low));
|
||||
const current = candles[i].close;
|
||||
|
||||
if (highest === lowest) {
|
||||
stochK.push(50);
|
||||
} else {
|
||||
stochK.push(((current - lowest) / (highest - lowest)) * 100);
|
||||
}
|
||||
}
|
||||
|
||||
// %D 계산 (K의 이동평균)
|
||||
const stochD = [];
|
||||
for (let i = 0; i < stochK.length; i++) {
|
||||
if (i < dPeriod - 1 || stochK[i] === null) {
|
||||
stochD.push(null);
|
||||
} else {
|
||||
const sum = stochK.slice(i - dPeriod + 1, i + 1).reduce((a, b) => a + (b || 0), 0);
|
||||
stochD.push(sum / dPeriod);
|
||||
}
|
||||
}
|
||||
|
||||
return { stochK, stochD };
|
||||
}
|
||||
|
||||
/**
|
||||
* 모든 지표 한 번에 계산
|
||||
*/
|
||||
function calculateAllIndicators(candles, config) {
|
||||
const results = {};
|
||||
|
||||
// MA
|
||||
if (config.maPeriods && config.maPeriods.length > 0) {
|
||||
Object.assign(results, calculateMA(candles, config.maPeriods));
|
||||
}
|
||||
|
||||
// RSI
|
||||
if (config.rsi) {
|
||||
results.rsi = calculateRSI(candles, config.rsiPeriod || 14);
|
||||
}
|
||||
|
||||
// MACD
|
||||
if (config.macd) {
|
||||
const macd = calculateMACD(
|
||||
candles,
|
||||
config.macdFastPeriod || 12,
|
||||
config.macdSlowPeriod || 26,
|
||||
config.macdSignalPeriod || 9
|
||||
);
|
||||
results.macdLine = macd.macdLine;
|
||||
results.macdSignal = macd.signalLine;
|
||||
results.macdHistogram = macd.histogram;
|
||||
}
|
||||
|
||||
// Stochastic
|
||||
if (config.stochastic) {
|
||||
const stoch = calculateStochastic(
|
||||
candles,
|
||||
config.stochasticKPeriod || 14,
|
||||
config.stochasticDPeriod || 3
|
||||
);
|
||||
results.stochasticK = stoch.stochK;
|
||||
results.stochasticD = stoch.stochD;
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
console.log('📊 Indicator Worker initialized');
|
||||
Reference in New Issue
Block a user