매매시그널 실행조건 화면 공용 적용

This commit is contained in:
Macbook
2026-06-22 00:02:59 +09:00
parent 0d14fd4ad2
commit 977dd54e64
10 changed files with 168 additions and 94 deletions
+28 -33
View File
@@ -5,6 +5,7 @@
import React, { useState, useEffect, useCallback } from 'react';
import type { Theme } from '../types';
import {
loadBacktestSettings,
saveLiveStrategySettings,
type LiveStrategySettingsDto,
} from '../utils/backendApi';
@@ -1347,6 +1348,15 @@ const StrategyPanel: React.FC<StrategyPanelProps> = ({
},
);
const [liveSaving, setLiveSaving] = useState(false);
const [backtestPositionMode, setBacktestPositionMode] = useState<'LONG_ONLY' | 'SIGNAL_ONLY'>('LONG_ONLY');
useEffect(() => {
void loadBacktestSettings().then(s => {
if (s?.positionMode === 'SIGNAL_ONLY' || s?.positionMode === 'LONG_ONLY') {
setBacktestPositionMode(s.positionMode);
}
});
}, []);
useEffect(() => {
if (liveSettingsProp) setLiveSettings(liveSettingsProp);
@@ -1354,7 +1364,12 @@ const StrategyPanel: React.FC<StrategyPanelProps> = ({
const persistLive = useCallback(async (patch: Partial<LiveStrategySettingsDto>) => {
if (virtualDriven) return;
const next: LiveStrategySettingsDto = { ...liveSettings, ...patch, market: liveMarket };
const next: LiveStrategySettingsDto = {
...liveSettings,
...patch,
market: liveMarket,
positionMode: backtestPositionMode,
};
if (next.isLiveCheck && next.strategyId != null) {
const synced = await syncStrategyTimeframesFromLayoutIfNeeded(next.strategyId);
if (!synced) return;
@@ -1370,7 +1385,7 @@ const StrategyPanel: React.FC<StrategyPanelProps> = ({
} finally {
setLiveSaving(false);
}
}, [liveSettings, liveMarket, onClearLiveMarkers, onLiveSettingsChange, virtualDriven]);
}, [liveSettings, liveMarket, onClearLiveMarkers, onLiveSettingsChange, virtualDriven, backtestPositionMode]);
const isOn = liveSettings.isLiveCheck;
const execType = liveSettings.executionType;
@@ -1502,38 +1517,18 @@ const StrategyPanel: React.FC<StrategyPanelProps> = ({
<SettingRow
className="stg-row--block"
label="포지션 종속성 모드"
desc="매도 시그널 발생 조건을 선택합니다. LONG_ONLY: 매수 이력이 있을 때만 매도 허용. SIGNAL_ONLY: 포지션 없이도 지표 규칙 충족 시 즉시 매도 시그널."
label="시그널 모드"
desc="백테스트 설정의 포지션 종속성 모드와 동일하게 적용됩니다. 변경은 설정 → 백테스트 설정에서 하세요."
>
<div className={`stg-radio-row${!isOn ? ' stg-radio-row--disabled' : ''}`}>
<label className="stg-radio-option stg-radio-option--blue">
<input
type="radio"
name="stg-pos-mode"
value="LONG_ONLY"
checked={(liveSettings.positionMode ?? 'LONG_ONLY') === 'LONG_ONLY'}
disabled={!isOn}
onChange={() => persistLive({ positionMode: 'LONG_ONLY' })}
/>
<span className="stg-radio-option-text">
<strong> (Long-Only)</strong>
<span> </span>
</span>
</label>
<label className="stg-radio-option stg-radio-option--orange">
<input
type="radio"
name="stg-pos-mode"
value="SIGNAL_ONLY"
checked={liveSettings.positionMode === 'SIGNAL_ONLY'}
disabled={!isOn}
onChange={() => persistLive({ positionMode: 'SIGNAL_ONLY' })}
/>
<span className="stg-radio-option-text">
<strong> (Signal-Only)</strong>
<span> , </span>
</span>
</label>
<div style={{
padding: '8px 10px', borderRadius: 6,
background: 'rgba(63,126,245,0.08)', border: '1px solid rgba(63,126,245,0.2)',
fontSize: 12, color: 'var(--text2)',
opacity: isOn ? 1 : 0.55,
}}>
{backtestPositionMode === 'LONG_ONLY'
? '보유 자산 기준 (Long-Only) — 매수 이력 있을 때만 매도 허용'
: '순수 지표 기준 (Signal-Only) — 포지션 무관, 지표 충족 시 즉시 매도'}
</div>
</SettingRow>
</SettingSection>