n봉 존재 조건 수정

This commit is contained in:
Macbook
2026-06-12 23:40:20 +09:00
parent b55349062f
commit 4a6be82c15
8 changed files with 365 additions and 32 deletions
+39 -9
View File
@@ -18,6 +18,12 @@ import {
simpleTemplateToNode,
type StrategyTemplateDef,
} from '../utils/strategyPresets';
import type { CandleRangeMode } from '../utils/strategyTypes';
import {
resolveCandleRangeMode,
candleRangeWindowBars,
formatCandleRangeClause,
} from '../utils/strategyTypes';
// ─── 타입 ─────────────────────────────────────────────────────────────────────
type LogicNodeType = 'AND' | 'OR' | 'NOT' | 'CONDITION' | 'TIMEFRAME';
@@ -33,6 +39,7 @@ interface ConditionDSL {
compareValue?: number;
slopePeriod?: number;
holdDays?: number;
candleRangeMode?: CandleRangeMode;
candleRange?: number;
}
@@ -572,8 +579,9 @@ const nodeToText = (node: LogicNode, DEF: DefType = DEF_DEFAULTS): string => {
const L = opts.find(o => o.value === c.leftField)?.label ?? c.leftField ?? c.indicatorType;
const R = opts.find(o => o.value === c.rightField)?.label ?? c.rightField ?? '';
const C = condLabel(c.conditionType);
if (R && R !== '선택안함') return `${c.indicatorType} - ${L} ${C} ${R}`;
return `${c.indicatorType} - ${L} ${C}`;
const rangeClause = formatCandleRangeClause(c);
if (R && R !== '선택안함') return `${c.indicatorType} - ${rangeClause}${L} ${C} ${R}`;
return `${c.indicatorType} - ${rangeClause}${L} ${C}`;
}
if (node.type === 'AND') {
const parts = (node.children ?? []).map(c => nodeToText(c, DEF));
@@ -712,14 +720,36 @@ const CondEditor: React.FC<CondEditorProps> = ({ cond, signalType, onChange, def
{/* 캔들 범위 */}
<div className="sp-cond-field">
<label className="sp-cond-lbl"> </label>
<select className="sp-cond-sel" value={cond.candleRange ?? 1}
onChange={e => onChange({ ...cond, candleRange: Number(e.target.value) })}>
<option value={1}> </option>
<option value={2}>2 </option>
<option value={3}>3 </option>
<option value={4}>4 </option>
<option value={5}>5 </option>
<select
className="sp-cond-sel"
value={resolveCandleRangeMode(cond)}
onChange={e => {
const mode = e.target.value as CandleRangeMode;
if (mode === 'CURRENT') {
onChange({ ...cond, candleRangeMode: mode, candleRange: 1 });
} else {
const n = candleRangeWindowBars(cond);
onChange({ ...cond, candleRangeMode: mode, candleRange: n >= 2 ? n : 4 });
}
}}
>
<option value="CURRENT"> </option>
<option value="EXISTS_IN">N봉 </option>
<option value="NOT_EXISTS_IN">N봉 </option>
</select>
{resolveCandleRangeMode(cond) !== 'CURRENT' && (
<input
type="number"
className="sp-cond-num sp-cond-num--inline"
min={2}
max={500}
value={candleRangeWindowBars(cond)}
onChange={e => onChange({
...cond,
candleRange: Math.max(2, parseInt(e.target.value, 10) || 4),
})}
/>
)}
</div>
{/* 조건대상1 */}
<div className="sp-cond-field">
@@ -4,7 +4,7 @@
*/
import React from 'react';
import type { LogicNode } from '../../utils/strategyTypes';
import { CONDITION_LABEL } from '../../utils/strategyTypes';
import { CONDITION_LABEL, resolveCandleRangeMode, candleRangeWindowBars } from '../../utils/strategyTypes';
import { getStrategyIndicatorDisplayName } from '../../utils/strategyPaletteStorage';
import { getIndicatorPaletteCategory } from '../strategyEditor/paletteCategories';
import { nodeToText } from '../../utils/strategyEditorShared';
@@ -56,9 +56,13 @@ const ConditionCard: React.FC<{ node: LogicNode }> = ({ node }) => {
const descText = fullText.startsWith(prefix) ? fullText.slice(prefix.length) : fullText;
const { left, mid: condStr, right } = splitDescByCondType(descText);
const candleRange = cond.candleRange != null && cond.candleRange > 0
? `${cond.candleRange}캔들 전`
: '현재 캔들';
const rangeMode = resolveCandleRangeMode(cond);
const rangeN = candleRangeWindowBars(cond);
const candleRangeLabel = rangeMode === 'CURRENT'
? '현재 캔들'
: rangeMode === 'EXISTS_IN'
? `최근 ${rangeN}봉 내 존재`
: `최근 ${rangeN}봉 내 미존재`;
const condLabelDisplay = CONDITION_LABEL[cond.conditionType] ?? (condStr || cond.conditionType);
@@ -71,7 +75,7 @@ const ConditionCard: React.FC<{ node: LogicNode }> = ({ node }) => {
<div className="scv-cond-fields">
<div className="scv-cond-field">
<span className="scv-cond-field-lbl"></span>
<span className="scv-cond-field-val">{candleRange}</span>
<span className="scv-cond-field-val">{candleRangeLabel}</span>
</div>
{left && (
<div className="scv-cond-field">