가상투자 로직 변경

This commit is contained in:
Macbook
2026-05-31 05:29:17 +09:00
parent 6da4821d9d
commit 85d7fea457
9 changed files with 39 additions and 182 deletions
+1 -2
View File
@@ -117,9 +117,8 @@ const PaperTradingPage: React.FC<Props> = ({
} finally {
setInitialLoading(false);
}
onPaperOrderFilled?.();
if (opts?.focusHistory) setRightTab('history');
}, [onPaperOrderFilled]);
}, []);
useEffect(() => {
void Promise.all([
+12 -10
View File
@@ -28,7 +28,7 @@ import {
} from './virtual/VirtualGridUnifiedHeader';
import type { VirtualCardDisplayMode } from './virtual/VirtualTargetCard';
import { useVirtualIndicatorSnapshots } from '../hooks/useVirtualIndicatorSnapshots';
import { useVirtualBackendTradeSignals } from '../hooks/useVirtualBackendTradeSignals';
import { PAPER_TRADES_CHANGED_EVENT } from '../utils/paperTradeEvents';
import { useVirtualTargetLiveStatus } from '../hooks/useVirtualTargetLiveStatus';
import type { ChartRealtimeSource } from '../hooks/useChartRealtimeData';
import {
@@ -195,15 +195,17 @@ const VirtualTradingPage: React.FC<Props> = ({
session.running,
);
useVirtualBackendTradeSignals({
enabled: paperTradingEnabled && paperAutoTradeEnabled,
session,
targets,
tickers,
paperAutoTradeBudgetPct,
positions: summary?.positions,
onFilled: () => void refreshPaperData({ focusHistory: true }),
});
/** 백엔드 자동 체결 후 UI 갱신(프론트는 주문 실행 안 함) */
useEffect(() => {
if (!session.running) return;
const onTradesChanged = () => { void refreshPaperData(); };
window.addEventListener(PAPER_TRADES_CHANGED_EVENT, onTradesChanged);
const pollId = window.setInterval(onTradesChanged, 20_000);
return () => {
window.removeEventListener(PAPER_TRADES_CHANGED_EVENT, onTradesChanged);
window.clearInterval(pollId);
};
}, [session.running, refreshPaperData]);
const mergedLiveStatus = useMemo(() => {
if (!session.running) return liveStatusByMarket;
@@ -21,7 +21,7 @@ const PaperLedgerTab: React.FC<Props> = ({ refreshKey = 0 }) => {
useEffect(() => {
let cancelled = false;
setLoading(true);
if (entries.length === 0) setLoading(true);
void loadPaperLedger({ page: 0, size: 50 }).then(page => {
if (!cancelled) {
setEntries(page.content);
@@ -29,6 +29,8 @@ const PaperLedgerTab: React.FC<Props> = ({ refreshKey = 0 }) => {
}
});
return () => { cancelled = true; };
// entries.length: 최초 로드만 스피너 — 갱신 시 목록 유지(깜빡임 방지)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [refreshKey]);
if (loading) return <p className="ptd-muted"> </p>;
@@ -85,8 +85,8 @@ const PaperLeftStrategyTab: React.FC<Props> = ({
</div>
<p className={`ptd-left-status ${paperAutoTradeEnabled ? 'ptd-left-status--on' : ''}`}>
{paperAutoTradeEnabled
? '자동매매 ON — 가상투자 Match 시 가상 계좌 자동 체결'
: '자동매매 OFF — 가상투자 타이틀바에서 변경'}
? '자동매매 ON — 가상 Match 후 서버가 전략 시그널·모의 체결(화면 꺼져도 동작)'
: '자동매매 OFF — 수동 주문만 모의 계좌에 체결'}
</p>
</>
);
@@ -110,7 +110,7 @@ export const VirtualSessionHeaderControls: React.FC<SessionProps> = ({
!paperTradingEnabled
? '설정 › 가상투자에서 가상매매를 활성화하세요'
: paperAutoTradeEnabled
? 'Match 충족 시 자동 매수·매도'
? 'Match 시 서버 자동 체결(모의·자동매매 ON, 화면 불필요)'
: '수동 주문만 가능'
}
>