전략알림 수정
This commit is contained in:
@@ -1129,6 +1129,11 @@ export async function loadStrategyTimeframes(strategyId: number): Promise<string
|
||||
return list?.length ? list : ['1m'];
|
||||
}
|
||||
|
||||
/** DB DSL TIMEFRAME 래핑 보정 (3분봉 전략이 1m으로 평가되는 레거시 수정) */
|
||||
export async function repairStrategyTimeframes(strategyId: number): Promise<void> {
|
||||
await request(`/strategies/${strategyId}/repair-timeframes`, { method: 'POST' });
|
||||
}
|
||||
|
||||
/** 차트 실시간 파이프라인 pin (STOMP warm-up) */
|
||||
export async function pinCandleWatch(market: string, candleType: string): Promise<void> {
|
||||
try {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { LogicNode } from './strategyTypes';
|
||||
import type { LogicNode, ConditionDSL } from './strategyTypes';
|
||||
import { generateNodeId } from './strategyTypes';
|
||||
import { subtreeToFlatOrphans } from './strategyFlowLayout';
|
||||
import {
|
||||
@@ -82,16 +82,79 @@ export function updateBranchRoot(
|
||||
};
|
||||
}
|
||||
|
||||
/** START 분봉 변경 시 조건 노드의 left/rightCandleType 동기화 */
|
||||
function syncSubtreeCandleTypes(node: LogicNode | null, candleType: string): LogicNode | null {
|
||||
if (!node) return null;
|
||||
const ct = normalizeStartCandleType(candleType);
|
||||
|
||||
if (node.type === 'CONDITION' && node.condition) {
|
||||
const cond = node.condition as ConditionDSL;
|
||||
return {
|
||||
...node,
|
||||
condition: {
|
||||
...cond,
|
||||
leftCandleType: ct,
|
||||
rightCandleType: ct,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (node.children?.length) {
|
||||
return {
|
||||
...node,
|
||||
children: node.children.map(c => syncSubtreeCandleTypes(c, ct)).filter(Boolean) as LogicNode[],
|
||||
};
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
function collectExplicitCandleTypesFromTree(node: LogicNode | null, out: Set<string>): void {
|
||||
if (!node) return;
|
||||
if (node.type === 'TIMEFRAME' && node.candleType) {
|
||||
out.add(normalizeStartCandleType(node.candleType));
|
||||
}
|
||||
if (node.type === 'CONDITION' && node.condition) {
|
||||
const c = node.condition as ConditionDSL;
|
||||
if (c.leftCandleType) out.add(normalizeStartCandleType(c.leftCandleType));
|
||||
if (c.rightCandleType) out.add(normalizeStartCandleType(c.rightCandleType));
|
||||
}
|
||||
node.children?.forEach(ch => collectExplicitCandleTypesFromTree(ch, out));
|
||||
}
|
||||
|
||||
function inferPrimaryCandleFromTree(root: LogicNode | null): string {
|
||||
const set = new Set<string>();
|
||||
collectExplicitCandleTypesFromTree(root, set);
|
||||
const non1m = [...set].filter(ct => ct !== '1m');
|
||||
if (non1m.length >= 1) return non1m[0];
|
||||
if (set.size >= 1) return [...set][0];
|
||||
return DEFAULT_START_CANDLE;
|
||||
}
|
||||
|
||||
export function updateStartCandleType(
|
||||
state: EditorConditionState,
|
||||
startId: string,
|
||||
candleType: string,
|
||||
): EditorConditionState {
|
||||
const ct = normalizeStartCandleType(candleType);
|
||||
const nextMeta = {
|
||||
...state.startMeta,
|
||||
[startId]: { candleType: ct },
|
||||
};
|
||||
|
||||
if (startId === START_NODE_ID) {
|
||||
return {
|
||||
...state,
|
||||
startMeta: nextMeta,
|
||||
root: syncSubtreeCandleTypes(state.root, ct),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
startMeta: {
|
||||
...state.startMeta,
|
||||
[startId]: { candleType: normalizeStartCandleType(candleType) },
|
||||
startMeta: nextMeta,
|
||||
extraRoots: {
|
||||
...state.extraRoots,
|
||||
[startId]: syncSubtreeCandleTypes(state.extraRoots[startId] ?? null, ct),
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -225,9 +288,12 @@ export function decodeConditionForEditor(dsl: LogicNode | null): EditorCondition
|
||||
};
|
||||
}
|
||||
|
||||
const inferred = inferPrimaryCandleFromTree(dsl);
|
||||
return {
|
||||
root: dsl,
|
||||
startMeta: defaultStartMeta(),
|
||||
startMeta: {
|
||||
[START_NODE_ID]: { candleType: inferred },
|
||||
},
|
||||
extraStartIds: [],
|
||||
extraRoots: {},
|
||||
startCombineOp: DEFAULT_START_COMBINE_OP,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { loadStrategyTimeframes, pinCandleWatch } from './backendApi';
|
||||
import { loadStrategyTimeframes, pinCandleWatch, repairStrategyTimeframes } from './backendApi';
|
||||
import { normalizeStartCandleType } from './strategyStartNodes';
|
||||
|
||||
/** 전략 DSL 평가 분봉 전체 pin — 1m 집계·상위 봉 warm-up */
|
||||
@@ -6,6 +6,11 @@ export async function pinStrategyEvaluationTimeframes(
|
||||
market: string,
|
||||
strategyId: number,
|
||||
): Promise<string[]> {
|
||||
try {
|
||||
await repairStrategyTimeframes(strategyId);
|
||||
} catch {
|
||||
/* 서버 미배포·권한 등 — timeframes 조회만 진행 */
|
||||
}
|
||||
const raw = await loadStrategyTimeframes(strategyId);
|
||||
const timeframes = [...new Set(raw.map(tf => normalizeStartCandleType(tf)))];
|
||||
if (timeframes.length === 0) timeframes.push('1m');
|
||||
|
||||
Reference in New Issue
Block a user