배포
This commit is contained in:
@@ -50,6 +50,7 @@ import '../styles/strategyEditorTheme.css';
|
|||||||
import { getKoreanName } from '../utils/marketNameCache';
|
import { getKoreanName } from '../utils/marketNameCache';
|
||||||
import { repairUtf8Mojibake } from '../utils/textEncoding';
|
import { repairUtf8Mojibake } from '../utils/textEncoding';
|
||||||
import { enrichStrategyNameMap, strategyNamesFromList } from '../utils/strategyNameResolver';
|
import { enrichStrategyNameMap, strategyNamesFromList } from '../utils/strategyNameResolver';
|
||||||
|
import { markStrategyIdsMissingUnlessValid } from '../utils/strategyMissingCache';
|
||||||
|
|
||||||
const LEFT_KEY = 'btd-left-width';
|
const LEFT_KEY = 'btd-left-width';
|
||||||
const RIGHT_KEY = 'btd-right-width';
|
const RIGHT_KEY = 'btd-right-width';
|
||||||
@@ -148,6 +149,10 @@ export function BacktestHistoryPage({ theme = 'dark' }: Props) {
|
|||||||
loadStrategies(),
|
loadStrategies(),
|
||||||
]);
|
]);
|
||||||
const baseNames = strategyNamesFromList(strategies);
|
const baseNames = strategyNamesFromList(strategies);
|
||||||
|
markStrategyIdsMissingUnlessValid(
|
||||||
|
strategies.map(s => s.id).filter((id): id is number => id != null && id > 0),
|
||||||
|
trades.map(t => t.strategyId),
|
||||||
|
);
|
||||||
const strategyNames = await enrichStrategyNameMap(
|
const strategyNames = await enrichStrategyNameMap(
|
||||||
baseNames,
|
baseNames,
|
||||||
trades.map(t => t.strategyId),
|
trades.map(t => t.strategyId),
|
||||||
@@ -166,6 +171,13 @@ export function BacktestHistoryPage({ theme = 'dark' }: Props) {
|
|||||||
loadStrategies(),
|
loadStrategies(),
|
||||||
]);
|
]);
|
||||||
const baseNames = strategyNamesFromList(strategies);
|
const baseNames = strategyNamesFromList(strategies);
|
||||||
|
markStrategyIdsMissingUnlessValid(
|
||||||
|
strategies.map(s => s.id).filter((id): id is number => id != null && id > 0),
|
||||||
|
[
|
||||||
|
...trades.map(t => t.strategyId),
|
||||||
|
...list.map(r => r.strategyId),
|
||||||
|
],
|
||||||
|
);
|
||||||
const strategyNames = await enrichStrategyNameMap(
|
const strategyNames = await enrichStrategyNameMap(
|
||||||
baseNames,
|
baseNames,
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState, type MutableR
|
|||||||
import TradingChart from '../TradingChart';
|
import TradingChart from '../TradingChart';
|
||||||
import type { BacktestSignal, StrategyDto } from '../../utils/backendApi';
|
import type { BacktestSignal, StrategyDto } from '../../utils/backendApi';
|
||||||
import { loadStrategyForNotification } from '../../utils/backendApi';
|
import { loadStrategyForNotification } from '../../utils/backendApi';
|
||||||
|
import { isStrategyMissingOnServer } from '../../utils/strategyMissingCache';
|
||||||
import type { ChartType, IndicatorConfig, OHLCVBar, Theme, Timeframe } from '../../types';
|
import type { ChartType, IndicatorConfig, OHLCVBar, Theme, Timeframe } from '../../types';
|
||||||
import { loadAnalysisCandles } from '../../utils/analysisChartData';
|
import { loadAnalysisCandles } from '../../utils/analysisChartData';
|
||||||
import type { ChartManager } from '../../utils/ChartManager';
|
import type { ChartManager } from '../../utils/ChartManager';
|
||||||
@@ -149,7 +150,7 @@ const BacktestAnalysisChart: React.FC<Props> = ({
|
|||||||
}, [strategy, timeframeRaw]);
|
}, [strategy, timeframeRaw]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!strategyId) {
|
if (!strategyId || isStrategyMissingOnServer(strategyId)) {
|
||||||
setStrategy(undefined);
|
setStrategy(undefined);
|
||||||
setStrategyLoading(false);
|
setStrategyLoading(false);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1113,9 +1113,9 @@ export async function loadStrategy(id: number): Promise<StrategyDto | null> {
|
|||||||
return request<StrategyDto>(`/strategies/${id}`);
|
return request<StrategyDto>(`/strategies/${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 알림·지표 표시 — missing 캐시 무시, 성공 시 캐시 해제 */
|
/** 알림·지표 표시 — missing 캐시 적용, 성공 시 캐시 해제 */
|
||||||
export async function loadStrategyForNotification(id: number): Promise<StrategyDto | null> {
|
export async function loadStrategyForNotification(id: number): Promise<StrategyDto | null> {
|
||||||
if (!hasRegisteredUser() || id <= 0) return null;
|
if (!hasRegisteredUser() || id <= 0 || isStrategyMissingOnServer(id)) return null;
|
||||||
const dto = await request<StrategyDto>(`/strategies/${id}`);
|
const dto = await request<StrategyDto>(`/strategies/${id}`);
|
||||||
if (dto) unmarkStrategyMissingOnServer(id);
|
if (dto) unmarkStrategyMissingOnServer(id);
|
||||||
return dto;
|
return dto;
|
||||||
|
|||||||
@@ -65,4 +65,19 @@ export function markStrategyMissingFromPath(pathOnly: string): void {
|
|||||||
if (m) markStrategyMissingOnServer(Number(m[1]));
|
if (m) markStrategyMissingOnServer(Number(m[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 목록에 없는 참조 ID를 missing 으로 기록 — 삭제된 전략 404 반복 방지 */
|
||||||
|
export function markStrategyIdsMissingUnlessValid(
|
||||||
|
validIds: Iterable<number>,
|
||||||
|
referencedIds: Iterable<number | null | undefined>,
|
||||||
|
): void {
|
||||||
|
const valid = new Set(
|
||||||
|
[...validIds].map(id => Math.trunc(id)).filter(id => id > 0),
|
||||||
|
);
|
||||||
|
for (const raw of referencedIds) {
|
||||||
|
if (raw == null) continue;
|
||||||
|
const id = Math.trunc(raw);
|
||||||
|
if (id > 0 && !valid.has(id)) markStrategyMissingOnServer(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hydrateStrategyMissingCache();
|
hydrateStrategyMissingCache();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
* 전략 ID → 이름 해석 (목록에 없거나 삭제된 전략 포함)
|
* 전략 ID → 이름 해석 (목록에 없거나 삭제된 전략 포함)
|
||||||
*/
|
*/
|
||||||
import { loadStrategyForNotification, type StrategyDto } from './backendApi';
|
import { loadStrategyForNotification, type StrategyDto } from './backendApi';
|
||||||
|
import { isStrategyMissingOnServer } from './strategyMissingCache';
|
||||||
|
|
||||||
/** 전략 목록 + 누락 ID별 단건 조회로 이름 맵 보강 */
|
/** 전략 목록 + 누락 ID별 단건 조회로 이름 맵 보강 */
|
||||||
export async function enrichStrategyNameMap(
|
export async function enrichStrategyNameMap(
|
||||||
@@ -12,7 +13,7 @@ export async function enrichStrategyNameMap(
|
|||||||
const missing = [...new Set(
|
const missing = [...new Set(
|
||||||
[...ids]
|
[...ids]
|
||||||
.map(id => (id != null && id > 0 ? Math.trunc(id) : null))
|
.map(id => (id != null && id > 0 ? Math.trunc(id) : null))
|
||||||
.filter((id): id is number => id != null && !out[id]),
|
.filter((id): id is number => id != null && !out[id] && !isStrategyMissingOnServer(id)),
|
||||||
)];
|
)];
|
||||||
if (!missing.length) return out;
|
if (!missing.length) return out;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user