Files
goldenChart/frontend/src/utils/virtualTargetMutations.ts
T
2026-05-28 20:48:28 +09:00

122 lines
3.6 KiB
TypeScript

import { saveLiveStrategySettings } from './backendApi';
import { getVirtualTargetMaxCount } from '../hooks/useAppSettings';
import {
isVirtualTargetAddAllowed,
virtualTargetLimitMessage,
} from '../utils/virtualTargetLimits';
import { syncVirtualTargetsToBackend } from './virtualLiveStrategySync';
import { resolveVirtualTargetStrategyId } from './virtualTargetStrategy';
import {
loadVirtualSession,
loadVirtualTargets,
notifyVirtualSessionChanged,
saveVirtualTargets,
type VirtualTargetItem,
} from './virtualTradingStorage';
export interface VirtualTargetMeta {
koreanName?: string;
englishName?: string;
}
export interface AddVirtualTargetOptions {
/** false면 한도 초과 시 알림 없이 스킵 (자동추가용) */
showLimitAlert?: boolean;
}
/** 가상투자 투자대상 목록에 종목 추가 (localStorage + DB) */
export async function addVirtualTarget(
market: string,
meta: VirtualTargetMeta = {},
opts: AddVirtualTargetOptions = {},
): Promise<VirtualTargetItem[]> {
const showLimitAlert = opts.showLimitAlert !== false;
const targets = loadVirtualTargets();
if (targets.some(t => t.market === market)) return targets;
const maxCount = getVirtualTargetMaxCount();
if (!isVirtualTargetAddAllowed(targets.length, maxCount)) {
if (showLimitAlert) window.alert(virtualTargetLimitMessage(maxCount));
return targets;
}
const session = loadVirtualSession();
const en = meta.englishName ?? market.replace(/^KRW-/, '');
const item: VirtualTargetItem = {
market,
/** null = 상단 기본 전략 사용 */
strategyId: null,
koreanName: meta.koreanName,
englishName: en,
};
const next = [...targets, item];
saveVirtualTargets(next);
await saveLiveStrategySettings({
market,
strategyId: session.globalStrategyId,
isLiveCheck: session.running,
isPinned: false,
executionType: session.executionType,
positionMode: session.positionMode,
skipWatchlistSync: true,
skipGlobalTemplate: true,
});
if (session.running && session.globalStrategyId) {
await syncVirtualTargetsToBackend(next, session, true);
}
notifyVirtualSessionChanged();
return next;
}
/** 가상투자 투자대상 목록에서 종목 제거 (localStorage + DB 비활성화) */
/** 투자대상 고정 상태 DB 저장 */
export async function persistVirtualTargetPinned(market: string, pinned: boolean): Promise<void> {
const session = loadVirtualSession();
const item = loadVirtualTargets().find(t => t.market === market);
await saveLiveStrategySettings({
market,
strategyId: item
? resolveVirtualTargetStrategyId(item, session.globalStrategyId)
: session.globalStrategyId,
isLiveCheck: session.running,
isPinned: pinned,
executionType: session.executionType,
positionMode: session.positionMode,
skipWatchlistSync: true,
skipGlobalTemplate: true,
});
}
export async function removeVirtualTarget(market: string): Promise<VirtualTargetItem[]> {
const targets = loadVirtualTargets();
const item = targets.find(t => t.market === market);
if (!item) return targets;
if (item.pinned) return targets;
const session = loadVirtualSession();
const next = targets.filter(t => t.market !== market);
saveVirtualTargets(next);
await saveLiveStrategySettings({
market,
strategyId: session.globalStrategyId,
isLiveCheck: false,
isPinned: false,
executionType: session.executionType,
positionMode: session.positionMode,
skipWatchlistSync: true,
skipGlobalTemplate: true,
});
if (session.running) {
await syncVirtualTargetsToBackend(next, session, true);
}
notifyVirtualSessionChanged();
return next;
}