Files
goldenChart/frontend/src/utils/trendSearchConditions.ts
T
2026-05-26 13:04:25 +09:00

192 lines
5.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/** 추세검색 조건 정의 — 정배열 / 상승세 / 거래량 / 보조지표 */
export type TrendConditionMode = 'filter';
export type TrendCategoryKey =
| 'maAlignEnabled'
| 'trendEnabled'
| 'volumePowerEnabled'
| 'indicatorEnabled';
export interface TrendConditionDef {
id: string;
category: 'ma' | 'trend' | 'volume' | 'indicator';
categoryLabel: string;
label: string;
desc: string;
mode: TrendConditionMode;
requestKey: keyof import('./backendApi').TrendSearchRequest;
categoryKey: TrendCategoryKey;
/** 조건 파라미터 UI */
params?: 'maConvergencePct' | 'ma20SlopeBars' | 'newHighBreakout' | 'volumeVsPrior' | 'minTurnover' | 'rsiBand' | 'adxMin';
}
export const TREND_CONDITION_DEFS: TrendConditionDef[] = [
// . 정배열
{
id: 'priceAboveMa',
category: 'ma',
categoryLabel: '. 정배열',
label: '주가 > 5·20·60 이평',
desc: '종가가 5·20·60일 이동평균선 위',
mode: 'filter',
requestKey: 'priceAboveMa',
categoryKey: 'maAlignEnabled',
},
{
id: 'maAlignment',
category: 'ma',
categoryLabel: '. 정배열',
label: '5 > 20 > 60 > 120 정배열',
desc: '단기 이평이 장기 이평 위에 배열',
mode: 'filter',
requestKey: 'maAlignment',
categoryKey: 'maAlignEnabled',
},
{
id: 'maConvergence',
category: 'ma',
categoryLabel: '. 정배열',
label: '이평밀집도 수렴 (선택)',
desc: '5·20·60 이평 간격이 N% 이내 (확산 전 포착)',
mode: 'filter',
requestKey: 'maConvergence',
categoryKey: 'maAlignEnabled',
params: 'maConvergencePct',
},
// Ⅱ. 상승세
{
id: 'ma20SlopeUp',
category: 'trend',
categoryLabel: 'Ⅱ. 상승세',
label: '20일 이평 연속 상승',
desc: '20일선(생명선) N봉 연속 우상향',
mode: 'filter',
requestKey: 'ma20SlopeUp',
categoryKey: 'trendEnabled',
params: 'ma20SlopeBars',
},
{
id: 'newHighBreakout',
category: 'trend',
categoryLabel: 'Ⅱ. 상승세',
label: '신고가 돌파·근접',
desc: 'N일 고가 돌파 또는 고가 대비 -M% 이내',
mode: 'filter',
requestKey: 'newHighBreakout',
categoryKey: 'trendEnabled',
params: 'newHighBreakout',
},
{
id: 'ichimokuAboveCloud',
category: 'trend',
categoryLabel: 'Ⅱ. 상승세',
label: '일목 구름대 상단',
desc: '주가 > 선행스팬1 · 선행스팬2',
mode: 'filter',
requestKey: 'ichimokuAboveCloud',
categoryKey: 'trendEnabled',
},
// Ⅲ. 돈과 힘
{
id: 'volumeVsPrior200',
category: 'volume',
categoryLabel: 'Ⅲ. 돈과 힘',
label: '직전 봉 대비 거래량',
desc: '일봉=전일, 분봉=직전 봉 대비 거래량 %',
mode: 'filter',
requestKey: 'volumeVsPrior200',
categoryKey: 'volumePowerEnabled',
params: 'volumeVsPrior',
},
{
id: 'minTurnover5dAvg',
category: 'volume',
categoryLabel: 'Ⅲ. 돈과 힘',
label: '5일 평균 거래대금',
desc: '최근 5일 평균 거래대금 하한 (억 원)',
mode: 'filter',
requestKey: 'minTurnover5dAvg',
categoryKey: 'volumePowerEnabled',
params: 'minTurnover',
},
{
id: 'volMa5Over20',
category: 'volume',
categoryLabel: 'Ⅲ. 돈과 힘',
label: '거래량 이평 정배열',
desc: '5일 거래량 이평 > 20일 거래량 이평',
mode: 'filter',
requestKey: 'volMa5Over20',
categoryKey: 'volumePowerEnabled',
},
// Ⅳ. 보조지표
{
id: 'macdGoldenCross',
category: 'indicator',
categoryLabel: 'Ⅳ. 보조지표',
label: 'MACD 골든크로스',
desc: 'MACD Line > Signal 또는 MACD > 0',
mode: 'filter',
requestKey: 'macdGoldenCross',
categoryKey: 'indicatorEnabled',
},
{
id: 'rsiBand',
category: 'indicator',
categoryLabel: 'Ⅳ. 보조지표',
label: 'RSI 구간',
desc: '과열·침체 구간 제외 (기본 50~70)',
mode: 'filter',
requestKey: 'rsiBand',
categoryKey: 'indicatorEnabled',
params: 'rsiBand',
},
{
id: 'dmiBullish',
category: 'indicator',
categoryLabel: 'Ⅳ. 보조지표',
label: '+DI > -DI · ADX',
desc: '추세 강도 ADX 하한 이상',
mode: 'filter',
requestKey: 'dmiBullish',
categoryKey: 'indicatorEnabled',
params: 'adxMin',
},
];
export const TREND_CATEGORY_ORDER: {
key: TrendCategoryKey;
label: string;
cat: TrendConditionDef['category'];
en: string;
}[] = [
{ key: 'maAlignEnabled', label: '. 정배열', cat: 'ma', en: 'Moving Average Alignment' },
{ key: 'trendEnabled', label: 'Ⅱ. 상승세', cat: 'trend', en: 'Trend & Momentum' },
{ key: 'volumePowerEnabled', label: 'Ⅲ. 돈과 힘', cat: 'volume', en: 'Volume & Liquidity' },
{ key: 'indicatorEnabled', label: 'Ⅳ. 보조지표', cat: 'indicator', en: 'Indicators' },
];
/** 카테고리 OFF 시 하위 조건까지 함께 끄기 위한 패치 */
export function buildCategoryTogglePatch(
catKey: TrendCategoryKey,
on: boolean,
): Partial<import('./backendApi').TrendSearchRequest> {
const patch: Partial<import('./backendApi').TrendSearchRequest> = { [catKey]: on };
if (!on) {
for (const def of TREND_CONDITION_DEFS.filter(d => d.categoryKey === catKey)) {
patch[def.requestKey] = false as never;
}
}
return patch;
}
export function countActiveTrendFilters(
filters: import('./backendApi').TrendSearchRequest,
): number {
let n = 0;
for (const def of TREND_CONDITION_DEFS) {
if (filters[def.categoryKey] && filters[def.requestKey]) n++;
}
return n;
}