차트 설정 수정
This commit is contained in:
@@ -42,103 +42,65 @@ export const VirtualSessionHeaderControls: React.FC<SessionProps> = ({
|
||||
onPaperAutoTradeEnabled,
|
||||
paperTradingEnabled = true,
|
||||
}) => (
|
||||
<div className="vtd-header-session">
|
||||
<div className="vtd-session-field">
|
||||
<span className="vtd-session-label">투자전략</span>
|
||||
<select
|
||||
className="vtd-session-select"
|
||||
value={session.globalStrategyId ?? ''}
|
||||
onChange={e => {
|
||||
const v = e.target.value;
|
||||
onStrategyChange(v ? Number(v) : null);
|
||||
}}
|
||||
>
|
||||
<option value="">— 선택 —</option>
|
||||
{strategies.map(s => (
|
||||
<option key={s.id} value={s.id}>{s.name}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div className="vtd-header-session vtd-header-session--compact">
|
||||
<select
|
||||
className="vtd-header-select vtd-header-select--strategy"
|
||||
aria-label="투자전략"
|
||||
value={session.globalStrategyId ?? ''}
|
||||
onChange={e => {
|
||||
const v = e.target.value;
|
||||
onStrategyChange(v ? Number(v) : null);
|
||||
}}
|
||||
>
|
||||
<option value="">전략 선택</option>
|
||||
{strategies.map(s => (
|
||||
<option key={s.id} value={s.id}>{s.name}</option>
|
||||
))}
|
||||
</select>
|
||||
|
||||
<div className="vtd-session-field">
|
||||
<span className="vtd-session-label">실행방식</span>
|
||||
<div className="vtd-view-toggle" role="group" aria-label="실행방식">
|
||||
<button
|
||||
type="button"
|
||||
className={`vtd-view-toggle-btn${session.executionType === 'CANDLE_CLOSE' ? ' vtd-view-toggle-btn--on' : ''}`}
|
||||
onClick={() => onExecutionTypeChange('CANDLE_CLOSE')}
|
||||
>
|
||||
봉 마감 직후
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={`vtd-view-toggle-btn${session.executionType === 'REALTIME_TICK' ? ' vtd-view-toggle-btn--on' : ''}`}
|
||||
onClick={() => onExecutionTypeChange('REALTIME_TICK')}
|
||||
>
|
||||
실시간 틱
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<select
|
||||
className="vtd-header-select vtd-header-select--narrow"
|
||||
aria-label="실행방식"
|
||||
value={session.executionType}
|
||||
onChange={e => onExecutionTypeChange(e.target.value as VirtualSessionConfig['executionType'])}
|
||||
>
|
||||
<option value="CANDLE_CLOSE">봉 마감 직후</option>
|
||||
<option value="REALTIME_TICK">실시간 틱</option>
|
||||
</select>
|
||||
|
||||
<div className="vtd-session-field">
|
||||
<span className="vtd-session-label">시그널 모드</span>
|
||||
<div className="vtd-view-toggle" role="group" aria-label="시그널 모드">
|
||||
<button
|
||||
type="button"
|
||||
className={`vtd-view-toggle-btn${session.positionMode === 'LONG_ONLY' ? ' vtd-view-toggle-btn--on' : ''}`}
|
||||
onClick={() => onPositionModeChange('LONG_ONLY')}
|
||||
>
|
||||
보유 자산 기준
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={`vtd-view-toggle-btn${session.positionMode === 'SIGNAL_ONLY' ? ' vtd-view-toggle-btn--on' : ''}`}
|
||||
onClick={() => onPositionModeChange('SIGNAL_ONLY')}
|
||||
>
|
||||
순수 지표 기준
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<select
|
||||
className="vtd-header-select vtd-header-select--narrow"
|
||||
aria-label="시그널 모드"
|
||||
value={session.positionMode}
|
||||
onChange={e => onPositionModeChange(e.target.value as VirtualSessionConfig['positionMode'])}
|
||||
>
|
||||
<option value="LONG_ONLY">보유 자산 기준</option>
|
||||
<option value="SIGNAL_ONLY">순수 지표 기준</option>
|
||||
</select>
|
||||
|
||||
<div className="vtd-session-field">
|
||||
<span className="vtd-session-label">자동매매</span>
|
||||
<div
|
||||
className="vtd-view-toggle"
|
||||
role="group"
|
||||
aria-label="자동매매"
|
||||
title={
|
||||
!paperTradingEnabled
|
||||
? '설정 › 가상투자에서 가상매매를 활성화하세요'
|
||||
: paperAutoTradeEnabled
|
||||
? 'Match 시 서버 자동 체결(모의·자동매매 ON, 화면 불필요)'
|
||||
: '수동 주문만 가능'
|
||||
}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className={`vtd-view-toggle-btn${paperAutoTradeEnabled ? ' vtd-view-toggle-btn--on' : ''}`}
|
||||
disabled={!paperTradingEnabled || !onPaperAutoTradeEnabled}
|
||||
onClick={() => onPaperAutoTradeEnabled?.(true)}
|
||||
>
|
||||
ON
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={`vtd-view-toggle-btn${!paperAutoTradeEnabled ? ' vtd-view-toggle-btn--on' : ''}`}
|
||||
disabled={!paperTradingEnabled || !onPaperAutoTradeEnabled}
|
||||
onClick={() => onPaperAutoTradeEnabled?.(false)}
|
||||
>
|
||||
OFF
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<select
|
||||
className="vtd-header-select vtd-header-select--narrow"
|
||||
aria-label="자동매매"
|
||||
title={
|
||||
!paperTradingEnabled
|
||||
? '설정 › 가상투자에서 가상매매를 활성화하세요'
|
||||
: undefined
|
||||
}
|
||||
value={paperAutoTradeEnabled ? 'on' : 'off'}
|
||||
disabled={!paperTradingEnabled || !onPaperAutoTradeEnabled}
|
||||
onChange={e => onPaperAutoTradeEnabled?.(e.target.value === 'on')}
|
||||
>
|
||||
<option value="off">자동매매 OFF</option>
|
||||
<option value="on">자동매매 ON</option>
|
||||
</select>
|
||||
|
||||
<div className="vtd-session-actions">
|
||||
<div className="vtd-session-actions vtd-session-actions--compact">
|
||||
<button
|
||||
type="button"
|
||||
className="bps-btn vtd-session-btn vtd-session-btn--start"
|
||||
disabled={session.running}
|
||||
onClick={onStart}
|
||||
title="가상투자 시작"
|
||||
>
|
||||
시작
|
||||
</button>
|
||||
@@ -147,6 +109,7 @@ export const VirtualSessionHeaderControls: React.FC<SessionProps> = ({
|
||||
className="bps-btn bps-btn--danger vtd-session-btn"
|
||||
disabled={!session.running}
|
||||
onClick={onStop}
|
||||
title="가상투자 종료"
|
||||
>
|
||||
종료
|
||||
</button>
|
||||
@@ -165,63 +128,36 @@ export const VirtualViewHeaderControls: React.FC<ViewProps> = ({
|
||||
onGridPresetChange,
|
||||
showGridLayoutPicker = true,
|
||||
}) => (
|
||||
<div className="vtd-header-view">
|
||||
<div className="vtd-header-view vtd-header-view--compact">
|
||||
{showGridLayoutPicker && onGridPresetChange && (
|
||||
<>
|
||||
<VirtualGridLayoutPicker
|
||||
value={gridPreset}
|
||||
onChange={onGridPresetChange}
|
||||
disabled={!showSignalChartToggle}
|
||||
/>
|
||||
<span className="vtd-grid-head-divider" aria-hidden="true" />
|
||||
</>
|
||||
<VirtualGridLayoutPicker
|
||||
value={gridPreset}
|
||||
onChange={onGridPresetChange}
|
||||
disabled={!showSignalChartToggle}
|
||||
/>
|
||||
)}
|
||||
{showSignalChartToggle && onGlobalDisplayModeChange && (
|
||||
<>
|
||||
<div className="vtd-grid-head-group" role="group" aria-label="전체 종목 신호·차트">
|
||||
<div className="vtd-view-toggle">
|
||||
<button
|
||||
type="button"
|
||||
className={`vtd-view-toggle-btn${globalDisplayMode === 'signal' ? ' vtd-view-toggle-btn--on' : ''}`}
|
||||
onClick={() => onGlobalDisplayModeChange('signal')}
|
||||
>
|
||||
신호
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={`vtd-view-toggle-btn${globalDisplayMode === 'chart' ? ' vtd-view-toggle-btn--on' : ''}`}
|
||||
onClick={() => onGlobalDisplayModeChange('chart')}
|
||||
>
|
||||
차트
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<span className="vtd-grid-head-divider" aria-hidden="true" />
|
||||
</>
|
||||
<select
|
||||
className="vtd-header-select vtd-header-select--narrow"
|
||||
aria-label="신호 또는 차트"
|
||||
value={globalDisplayMode}
|
||||
onChange={e => onGlobalDisplayModeChange(e.target.value as VirtualCardDisplayMode)}
|
||||
>
|
||||
<option value="signal">신호</option>
|
||||
<option value="chart">차트</option>
|
||||
</select>
|
||||
)}
|
||||
<div className="vtd-grid-head-group" role="group" aria-label="카드 표시 방식">
|
||||
<div className="vtd-view-toggle">
|
||||
<button
|
||||
type="button"
|
||||
className={`vtd-view-toggle-btn${viewMode === 'summary' ? ' vtd-view-toggle-btn--on' : ''}`}
|
||||
onClick={() => onViewModeChange('summary')}
|
||||
>
|
||||
요약표시
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={`vtd-view-toggle-btn${viewMode === 'detail' ? ' vtd-view-toggle-btn--on' : ''}`}
|
||||
onClick={() => onViewModeChange('detail')}
|
||||
>
|
||||
상세표시
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<select
|
||||
className="vtd-header-select vtd-header-select--narrow"
|
||||
aria-label="카드 표시 방식"
|
||||
value={viewMode}
|
||||
onChange={e => onViewModeChange(e.target.value as VirtualCardViewMode)}
|
||||
>
|
||||
<option value="summary">요약표시</option>
|
||||
<option value="detail">상세표시</option>
|
||||
</select>
|
||||
{session.running && (
|
||||
<>
|
||||
<span className="vtd-grid-head-divider" aria-hidden="true" />
|
||||
<span className="vtd-grid-live">실시간 갱신 3초</span>
|
||||
</>
|
||||
<span className="vtd-grid-live" title="3초마다 갱신">실시간</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -88,8 +88,6 @@ const VirtualLeftTargetPanel: React.FC<Props> = ({
|
||||
}, [addedSet, targets, globalStrategyId, onTargetsChange, onSelectMarket, virtualTargetMaxCount]);
|
||||
|
||||
const handleRemove = useCallback((market: string) => {
|
||||
const item = targets.find(t => t.market === market);
|
||||
if (item?.pinned) return;
|
||||
onTargetsChange(targets.filter(t => t.market !== market));
|
||||
}, [targets, onTargetsChange]);
|
||||
|
||||
@@ -119,6 +117,7 @@ const VirtualLeftTargetPanel: React.FC<Props> = ({
|
||||
addedMarkets={addedSet}
|
||||
maxTargetsReached={atTargetLimit}
|
||||
onAdd={handleAdd}
|
||||
onRemove={handleRemove}
|
||||
onSelect={onSelectMarket}
|
||||
onClose={closeDropdown}
|
||||
/>
|
||||
@@ -174,9 +173,8 @@ const VirtualLeftTargetPanel: React.FC<Props> = ({
|
||||
<button
|
||||
type="button"
|
||||
className="vtd-target-remove"
|
||||
title={item.pinned ? '고정된 종목은 삭제할 수 없습니다' : '목록에서 제거'}
|
||||
title="목록에서 제거"
|
||||
aria-label="목록에서 제거"
|
||||
disabled={!!item.pinned}
|
||||
onClick={e => { e.stopPropagation(); handleRemove(item.market); }}
|
||||
>
|
||||
✕
|
||||
|
||||
@@ -12,6 +12,7 @@ interface Props {
|
||||
onStop: () => void;
|
||||
}
|
||||
|
||||
/** 레거시 — VirtualSessionHeaderControls 와 동일 드롭다운 레이아웃 */
|
||||
const VirtualSessionToolbar: React.FC<Props> = ({
|
||||
session,
|
||||
strategies,
|
||||
@@ -21,65 +22,43 @@ const VirtualSessionToolbar: React.FC<Props> = ({
|
||||
onStart,
|
||||
onStop,
|
||||
}) => (
|
||||
<div className="vtd-session-toolbar">
|
||||
<div className="vtd-session-field">
|
||||
<span className="vtd-session-label">투자전략</span>
|
||||
<select
|
||||
className="vtd-session-select"
|
||||
value={session.globalStrategyId ?? ''}
|
||||
onChange={e => {
|
||||
const v = e.target.value;
|
||||
onStrategyChange(v ? Number(v) : null);
|
||||
}}
|
||||
>
|
||||
<option value="">— 선택 —</option>
|
||||
{strategies.map(s => (
|
||||
<option key={s.id} value={s.id}>{s.name}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div className="vtd-session-toolbar vtd-header-session--compact">
|
||||
<select
|
||||
className="vtd-header-select vtd-header-select--strategy"
|
||||
aria-label="투자전략"
|
||||
value={session.globalStrategyId ?? ''}
|
||||
onChange={e => {
|
||||
const v = e.target.value;
|
||||
onStrategyChange(v ? Number(v) : null);
|
||||
}}
|
||||
>
|
||||
<option value="">전략 선택</option>
|
||||
{strategies.map(s => (
|
||||
<option key={s.id} value={s.id}>{s.name}</option>
|
||||
))}
|
||||
</select>
|
||||
|
||||
<div className="vtd-session-field">
|
||||
<span className="vtd-session-label">실행방식</span>
|
||||
<div className="vtd-view-toggle" role="group" aria-label="실행방식">
|
||||
<button
|
||||
type="button"
|
||||
className={`vtd-view-toggle-btn${session.executionType === 'CANDLE_CLOSE' ? ' vtd-view-toggle-btn--on' : ''}`}
|
||||
onClick={() => onExecutionTypeChange('CANDLE_CLOSE')}
|
||||
>
|
||||
봉 마감 직후
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={`vtd-view-toggle-btn${session.executionType === 'REALTIME_TICK' ? ' vtd-view-toggle-btn--on' : ''}`}
|
||||
onClick={() => onExecutionTypeChange('REALTIME_TICK')}
|
||||
>
|
||||
실시간 틱
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<select
|
||||
className="vtd-header-select vtd-header-select--narrow"
|
||||
aria-label="실행방식"
|
||||
value={session.executionType}
|
||||
onChange={e => onExecutionTypeChange(e.target.value as VirtualSessionConfig['executionType'])}
|
||||
>
|
||||
<option value="CANDLE_CLOSE">봉 마감 직후</option>
|
||||
<option value="REALTIME_TICK">실시간 틱</option>
|
||||
</select>
|
||||
|
||||
<div className="vtd-session-field">
|
||||
<span className="vtd-session-label">시그널 모드</span>
|
||||
<div className="vtd-view-toggle" role="group" aria-label="시그널 모드">
|
||||
<button
|
||||
type="button"
|
||||
className={`vtd-view-toggle-btn${session.positionMode === 'LONG_ONLY' ? ' vtd-view-toggle-btn--on' : ''}`}
|
||||
onClick={() => onPositionModeChange('LONG_ONLY')}
|
||||
>
|
||||
보유 자산 기준
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={`vtd-view-toggle-btn${session.positionMode === 'SIGNAL_ONLY' ? ' vtd-view-toggle-btn--on' : ''}`}
|
||||
onClick={() => onPositionModeChange('SIGNAL_ONLY')}
|
||||
>
|
||||
순수 지표 기준
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<select
|
||||
className="vtd-header-select vtd-header-select--narrow"
|
||||
aria-label="시그널 모드"
|
||||
value={session.positionMode}
|
||||
onChange={e => onPositionModeChange(e.target.value as VirtualSessionConfig['positionMode'])}
|
||||
>
|
||||
<option value="LONG_ONLY">보유 자산 기준</option>
|
||||
<option value="SIGNAL_ONLY">순수 지표 기준</option>
|
||||
</select>
|
||||
|
||||
<div className="vtd-session-actions">
|
||||
<div className="vtd-session-actions vtd-session-actions--compact">
|
||||
<button
|
||||
type="button"
|
||||
className="bps-btn vtd-session-btn vtd-session-btn--start"
|
||||
|
||||
Reference in New Issue
Block a user