다중 시간봉 전략 설정기능 추가

This commit is contained in:
Macbook
2026-05-25 02:49:39 +09:00
parent cc01f311bc
commit 30dedc4abc
17 changed files with 1903 additions and 249 deletions
@@ -2,10 +2,18 @@ import React from 'react';
import type { LogicNode } from '../../utils/strategyTypes';
import { nodeToText, type DefType } from '../../utils/strategyEditorShared';
import { getIndicatorPaletteCategory } from './paletteCategories';
import {
collectEditorBranches,
normalizeStartCombineOp,
type EditorConditionState,
} from '../../utils/strategyConditionSerde';
import { formatStartCandleLabel } from '../../utils/strategyStartNodes';
interface Props {
buyCondition: LogicNode | null;
sellCondition: LogicNode | null;
buyEditorState?: EditorConditionState;
sellEditorState?: EditorConditionState;
orphanCount: number;
def: DefType;
}
@@ -81,34 +89,106 @@ function renderNode(node: LogicNode, def: DefType): React.ReactNode {
);
}
if (node.type === 'TIMEFRAME') {
const inner = node.children?.[0];
const tf = formatStartCandleLabel(node.candleType ?? '1m');
return inner ? (
<>
<span className="se-formula-tf">[{tf}]</span>
{' '}
{renderNode(inner, def)}
</>
) : (
<span className="se-formula-empty">[{tf} ]</span>
);
}
return null;
}
function renderSignalBranches(
editorState: EditorConditionState | undefined,
fallbackRoot: LogicNode | null,
def: DefType,
): React.ReactNode {
const branches = editorState
? collectEditorBranches(editorState)
: fallbackRoot
? [{ candleType: '1m', root: fallbackRoot }]
: [];
if (branches.length === 0) {
return <span className="se-formula-empty">( )</span>;
}
if (branches.length === 1) {
const { candleType, root } = branches[0];
if (!root) return <span className="se-formula-empty">( )</span>;
return (
<>
<span className="se-formula-tf">[{formatStartCandleLabel(candleType)}]</span>
{' '}
{renderNode(root, def)}
</>
);
}
const combineOp = normalizeStartCombineOp(editorState?.startCombineOp);
const combineClass = combineOp === 'AND' ? 'se-formula-logic--and' : 'se-formula-logic--or';
return (
<>
<span className="se-formula-punc">(</span>
{branches.map((branch, i) => (
<React.Fragment key={`${branch.candleType}-${i}`}>
{i > 0 ? (
<span className={`se-formula-logic ${combineClass}`}> {combineOp} </span>
) : null}
{branch.root ? (
<>
<span className="se-formula-tf">[{formatStartCandleLabel(branch.candleType)}]</span>
{' '}
{renderNode(branch.root, def)}
</>
) : (
<span className="se-formula-empty">[{formatStartCandleLabel(branch.candleType)} ]</span>
)}
</React.Fragment>
))}
<span className="se-formula-punc">)</span>
</>
);
}
export default function LogicExpressionPreview({
buyCondition,
sellCondition,
buyEditorState,
sellEditorState,
orphanCount,
def,
}: Props) {
const hasBody = buyCondition || sellCondition;
const hasBody = buyCondition || sellCondition
|| (buyEditorState && collectEditorBranches(buyEditorState).some(b => b.root))
|| (sellEditorState && collectEditorBranches(sellEditorState).some(b => b.root));
return (
<div className="se-terminal-text se-terminal-text--rich">
{!hasBody && (
<span className="se-formula-empty">( )</span>
)}
{buyCondition && (
{(buyCondition || buyEditorState) && (
<div className="se-formula-line">
<span className="se-formula-signal se-formula-signal--buy">[]</span>
{' '}
{renderNode(buyCondition, def)}
{renderSignalBranches(buyEditorState, buyCondition, def)}
</div>
)}
{sellCondition && (
{(sellCondition || sellEditorState) && (
<div className="se-formula-line">
<span className="se-formula-signal se-formula-signal--sell">[]</span>
{' '}
{renderNode(sellCondition, def)}
{renderSignalBranches(sellEditorState, sellCondition, def)}
</div>
)}
{orphanCount > 0 && (