지표탭 추가

This commit is contained in:
Macbook
2026-05-27 09:32:26 +09:00
parent d0985f8f0f
commit 8876dbd752
12 changed files with 595 additions and 73 deletions
+39 -2
View File
@@ -8,7 +8,7 @@ import type { Theme } from '../types/index';
import { loadStrategies, saveStrategy, deleteStrategy, type StrategyDto as ApiStrategyDto } from '../utils/backendApi';
import type { LogicNode } from '../utils/strategyTypes';
import {
buildStrategyEditorDef,
buildStrategyEditorDefFromSettings,
loadStratsLocal,
saveStratsLocal,
mergeAtRoot,
@@ -18,6 +18,8 @@ import {
genId,
type StrategyDto,
} from '../utils/strategyEditorShared';
import { syncLogicNodeWithGlobalDef } from '../utils/strategyDefSync';
import { useIndicatorSettings } from '../hooks/useIndicatorSettings';
import { findLogicNode, getIndicatorPeriodLabel } from '../utils/strategyFlowLayout';
import {
decodeConditionForEditor,
@@ -128,7 +130,12 @@ function normalizeTabLayoutState(snap: SignalFlowLayoutSnapshot) {
}
export default function StrategyEditorPage({ theme }: Props) {
const DEF = useMemo(() => buildStrategyEditorDef(), []);
const { getParams, getVisualConfig, settingsRevision } = useIndicatorSettings();
const DEF = useMemo(
() => buildStrategyEditorDefFromSettings(getParams, getVisualConfig),
[getParams, getVisualConfig, settingsRevision],
);
const settingsSyncRef = useRef(0);
const [strategies, setStrategies] = useState<StrategyDto[]>(() => loadStratsLocal());
const [selectedId, setSelectedId] = useState<number | null>(null);
@@ -247,6 +254,36 @@ export default function StrategyEditorPage({ theme }: Props) {
const orphanTotal = buyOrphans.length + sellOrphans.length;
/** 보조지표 설정 변경 시 오버라이드되지 않은 조건 노드 기준값 동기화 */
useEffect(() => {
if (settingsRevision <= settingsSyncRef.current) return;
settingsSyncRef.current = settingsRevision;
const syncExtraRoots = (
roots: Record<string, LogicNode | null>,
signalType: 'buy' | 'sell',
) => {
const next: Record<string, LogicNode | null> = {};
for (const [key, node] of Object.entries(roots)) {
next[key] = node ? syncLogicNodeWithGlobalDef(node, DEF, signalType) : null;
}
return next;
};
setBuyCondition(prev => (prev ? syncLogicNodeWithGlobalDef(prev, DEF, 'buy') : prev));
setSellCondition(prev => (prev ? syncLogicNodeWithGlobalDef(prev, DEF, 'sell') : prev));
setBuyOrphans(prev => prev.map(n => syncLogicNodeWithGlobalDef(n, DEF, 'buy')));
setSellOrphans(prev => prev.map(n => syncLogicNodeWithGlobalDef(n, DEF, 'sell')));
setBuyLayout(prev => ({
...prev,
extraRoots: syncExtraRoots(prev.extraRoots ?? {}, 'buy'),
}));
setSellLayout(prev => ({
...prev,
extraRoots: syncExtraRoots(prev.extraRoots ?? {}, 'sell'),
}));
}, [settingsRevision, DEF]);
const layoutStrategyKey = selectedId != null ? String(selectedId) : 'draft';
const persistFlowLayout = useCallback((strategyKey: string) => {