..
This commit is contained in:
@@ -63,85 +63,85 @@ const AutoTrading: React.FC<AutoTradingProps> = ({ marketMode, stocks, configs,
|
||||
const filteredGroups = groups.filter(g => g.codes.some(code => stocks.find(s => s.code === code)?.market === marketMode));
|
||||
|
||||
return (
|
||||
<div className="space-y-12 animate-in slide-in-from-bottom-6 duration-500 pb-24">
|
||||
<div className="flex justify-between items-center bg-white p-12 rounded-[4rem] shadow-sm border border-slate-100">
|
||||
<div className="space-y-6 animate-in slide-in-from-bottom-6 duration-500 pb-20 pr-4">
|
||||
<div className="flex justify-between items-center bg-white p-6 rounded-2xl shadow-sm border border-slate-100">
|
||||
<div>
|
||||
<h3 className="text-3xl font-black text-slate-800 uppercase tracking-tight flex items-center gap-5">
|
||||
<Cpu className="text-emerald-500" size={36} /> {marketMode === MarketType.DOMESTIC ? '국내' : '해외'} 매매 엔진
|
||||
<h3 className="text-xl font-black text-slate-800 uppercase tracking-tighter flex items-center gap-3">
|
||||
<Cpu className="text-emerald-500" size={24} /> {marketMode === MarketType.DOMESTIC ? '국내' : '해외'} 매매 엔진
|
||||
</h3>
|
||||
<p className="text-base font-bold text-slate-400 uppercase tracking-widest mt-3 flex items-center gap-3">
|
||||
<span className="relative flex h-3 w-3">
|
||||
<p className="text-[12px] font-black text-slate-400 uppercase tracking-widest mt-1 flex items-center gap-2">
|
||||
<span className="relative flex h-2 w-2">
|
||||
<span className={`animate-ping absolute inline-flex h-full w-full rounded-full opacity-75 ${configs.filter(c => c.active && c.market === marketMode).length > 0 ? 'bg-emerald-400' : 'bg-slate-300'}`}></span>
|
||||
<span className={`relative inline-flex rounded-full h-3 w-3 ${configs.filter(c => c.active && c.market === marketMode).length > 0 ? 'bg-emerald-500' : 'bg-slate-400'}`}></span>
|
||||
<span className={`relative inline-flex rounded-full h-2 w-2 ${configs.filter(c => c.active && c.market === marketMode).length > 0 ? 'bg-emerald-500' : 'bg-slate-400'}`}></span>
|
||||
</span>
|
||||
현재 {configs.filter(c => c.active && c.market === marketMode).length}개의 로봇 에이전트 활성화됨
|
||||
{configs.filter(c => c.active && c.market === marketMode).length}개의 로봇 활성화됨
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => { setShowAddModal(true); setTargetType('SINGLE'); }}
|
||||
className="bg-slate-900 text-white px-12 py-6 rounded-[2.5rem] font-black text-base uppercase tracking-widest flex items-center gap-4 hover:bg-slate-800 transition-all shadow-2xl shadow-slate-300 active:scale-95"
|
||||
className="bg-slate-900 text-white px-6 py-2.5 rounded-xl font-black text-[12px] uppercase tracking-widest flex items-center gap-2 hover:bg-slate-800 transition-all shadow-md active:scale-95"
|
||||
>
|
||||
<Plus size={24} /> 새 매매 전략 배포
|
||||
<Plus size={18} /> 새 전략 배포
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-10">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{configs.filter(c => c.market === marketMode).map(config => (
|
||||
<div key={config.id} className={`bg-white p-12 rounded-[4rem] shadow-sm border transition-all relative overflow-hidden group hover:shadow-2xl ${config.active ? 'border-emerald-200' : 'border-slate-100 grayscale-[0.5]'}`}>
|
||||
<div className={`absolute top-0 left-0 w-full h-2.5 transition-colors ${config.active ? (config.groupId ? 'bg-indigo-500' : (config.type === 'ACCUMULATION' ? 'bg-blue-500' : 'bg-orange-500')) : 'bg-slate-300'}`}></div>
|
||||
<div key={config.id} className={`bg-white p-5 rounded-2xl shadow-sm border transition-all relative overflow-hidden group hover:shadow-md ${config.active ? 'border-emerald-200' : 'border-slate-100 grayscale-[0.5]'}`}>
|
||||
<div className={`absolute top-0 left-0 w-full h-1.5 transition-colors ${config.active ? (config.groupId ? 'bg-indigo-500' : (config.type === 'ACCUMULATION' ? 'bg-blue-500' : 'bg-orange-500')) : 'bg-slate-300'}`}></div>
|
||||
|
||||
<div className="flex justify-between items-start mb-10">
|
||||
<div className="flex items-center gap-6">
|
||||
<div className={`p-5 rounded-3xl shadow-sm transition-colors ${config.active ? (config.groupId ? 'bg-indigo-50 text-indigo-600' : (config.type === 'ACCUMULATION' ? 'bg-blue-50 text-blue-600' : 'bg-orange-50 text-orange-600')) : 'bg-slate-100 text-slate-400'}`}>
|
||||
{config.groupId ? <Layers size={32} /> : <Activity size={32} />}
|
||||
<div className="flex justify-between items-start mb-6">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className={`p-3 rounded-xl shadow-sm transition-colors ${config.active ? (config.groupId ? 'bg-indigo-50 text-indigo-600' : (config.type === 'ACCUMULATION' ? 'bg-blue-50 text-blue-600' : 'bg-orange-50 text-orange-600')) : 'bg-slate-100 text-slate-400'}`}>
|
||||
{config.groupId ? <Layers size={20} /> : <Activity size={20} />}
|
||||
</div>
|
||||
<div>
|
||||
<h4 className={`font-black text-2xl leading-none mb-2 transition-colors ${config.active ? 'text-slate-900' : 'text-slate-400'}`}>{config.stockName}</h4>
|
||||
<p className="text-[12px] text-slate-400 font-mono font-bold tracking-widest uppercase">{config.groupId ? 'GROUP AGENT' : config.stockCode}</p>
|
||||
<h4 className={`font-black text-[16px] leading-tight mb-0.5 transition-colors ${config.active ? 'text-slate-900' : 'text-slate-400'}`}>{config.stockName}</h4>
|
||||
<p className="text-[10px] text-slate-400 font-mono font-bold tracking-widest uppercase">{config.groupId ? 'GROUP AGENT' : config.stockCode}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 활성화 토글 스위치 */}
|
||||
<button
|
||||
onClick={() => onToggleConfig(config.id)}
|
||||
className={`relative inline-flex h-8 w-14 items-center rounded-full transition-all focus:outline-none ${config.active ? 'bg-emerald-500' : 'bg-slate-200'}`}
|
||||
className={`relative inline-flex h-5 w-9 items-center rounded-full transition-all focus:outline-none ${config.active ? 'bg-emerald-500' : 'bg-slate-200'}`}
|
||||
>
|
||||
<span className={`inline-block h-5 w-5 transform rounded-full bg-white transition-transform ${config.active ? 'translate-x-7' : 'translate-x-2'}`} />
|
||||
<span className={`inline-block h-3.5 w-3.5 transform rounded-full bg-white shadow-sm transition-transform ${config.active ? 'translate-x-4.5' : 'translate-x-1'}`} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-6">
|
||||
<div className={`p-8 rounded-[3rem] space-y-5 border transition-colors ${config.active ? 'bg-slate-50/80 border-slate-100' : 'bg-slate-50/30 border-transparent'}`}>
|
||||
<div className="flex justify-between items-center text-[12px] font-black uppercase tracking-[0.2em]">
|
||||
<div className="space-y-4">
|
||||
<div className={`p-4 rounded-xl space-y-3 border transition-colors ${config.active ? 'bg-slate-50/80 border-slate-100' : 'bg-slate-50/30 border-transparent'}`}>
|
||||
<div className="flex justify-between items-center text-[11px] font-black uppercase tracking-widest">
|
||||
<span className="text-slate-400">오퍼레이션</span>
|
||||
<span className={config.active ? (config.groupId ? 'text-indigo-600' : 'text-slate-600') : 'text-slate-300'}>{config.groupId ? '그룹 일괄' : '개별 자산'}</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center text-[12px] font-black uppercase tracking-[0.2em]">
|
||||
<div className="flex justify-between items-center text-[11px] font-black uppercase tracking-widest">
|
||||
<span className="text-slate-400">코어 전략</span>
|
||||
<span className={`px-3 py-1 rounded-lg transition-colors ${config.active ? (config.type === 'ACCUMULATION' ? 'bg-blue-100 text-blue-600' : 'bg-orange-100 text-orange-600') : 'bg-slate-100 text-slate-300'}`}>
|
||||
<span className={`px-2 py-0.5 rounded-lg transition-colors ${config.active ? (config.type === 'ACCUMULATION' ? 'bg-blue-100 text-blue-600' : 'bg-orange-100 text-orange-600') : 'bg-slate-100 text-slate-300'}`}>
|
||||
{config.type === 'ACCUMULATION' ? '적립식 매수' : 'TS 자동매매'}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center text-base font-bold">
|
||||
<span className="text-slate-400 uppercase tracking-widest text-[12px]">스케줄링</span>
|
||||
<span className={`flex items-center gap-3 transition-colors ${config.active ? 'text-slate-700' : 'text-slate-300'}`}><Calendar size={20} className="text-slate-400" /> {getDayLabel(config)}</span>
|
||||
<div className="flex justify-between items-center text-[12px] font-bold">
|
||||
<span className="text-slate-400 uppercase tracking-widest text-[11px]">스케줄링</span>
|
||||
<span className={`flex items-center gap-2 transition-colors ${config.active ? 'text-slate-700' : 'text-slate-300'}`}><Calendar size={14} className="text-slate-400" /> {getDayLabel(config)}</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center text-base font-bold">
|
||||
<span className="text-slate-400 uppercase tracking-widest text-[12px]">실행정보</span>
|
||||
<span className={`flex items-center gap-3 transition-colors ${config.active ? 'text-slate-700' : 'text-slate-300'}`}><Clock size={20} className="text-slate-400" /> {config.executionTime} / {config.quantity}주</span>
|
||||
<div className="flex justify-between items-center text-[12px] font-bold">
|
||||
<span className="text-slate-400 uppercase tracking-widest text-[11px]">실행정보</span>
|
||||
<span className={`flex items-center gap-2 transition-colors ${config.active ? 'text-slate-700' : 'text-slate-300'}`}><Clock size={14} className="text-slate-400" /> {config.executionTime} / {config.quantity}주</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pt-8 border-t border-slate-100 flex justify-between items-center">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className={`w-3 h-3 rounded-full transition-colors ${config.active ? 'bg-emerald-500' : 'bg-slate-300'}`}></span>
|
||||
<span className="text-[12px] font-black text-slate-400 uppercase tracking-widest">{config.active ? '에이전트 운용 중' : '일시 중단됨'}</span>
|
||||
<div className="pt-4 border-t border-slate-100 flex justify-between items-center">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className={`w-2 h-2 rounded-full transition-colors ${config.active ? 'bg-emerald-500' : 'bg-slate-300'}`}></span>
|
||||
<span className="text-[11px] font-black text-slate-400 uppercase tracking-widest">{config.active ? '에이전트 운용 중' : '일시 중단됨'}</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => onDeleteConfig(config.id)}
|
||||
className="p-4 text-slate-300 hover:text-rose-500 hover:bg-rose-50 rounded-[1.5rem] transition-all"
|
||||
className="p-2 text-slate-300 hover:text-rose-500 hover:bg-rose-50 rounded-lg transition-all"
|
||||
>
|
||||
<Trash2 size={24} />
|
||||
<Trash2 size={18} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -149,44 +149,43 @@ const AutoTrading: React.FC<AutoTradingProps> = ({ marketMode, stocks, configs,
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* 전략 추가 모달 (기존 동일) */}
|
||||
{showAddModal && (
|
||||
<div className="fixed inset-0 z-[100] bg-slate-900/60 backdrop-blur-md flex items-center justify-center p-6">
|
||||
<div className="bg-white w-full max-w-2xl rounded-[4rem] p-16 shadow-2xl animate-in zoom-in-95 duration-300 border border-slate-100 overflow-hidden">
|
||||
<div className="flex justify-between items-center mb-12">
|
||||
<h3 className="text-4xl font-black text-slate-900 uppercase tracking-tight flex items-center gap-5">
|
||||
<Zap className="text-yellow-400 fill-yellow-400" /> 로봇 전략 설계
|
||||
<div className="fixed inset-0 z-[100] bg-slate-900/60 backdrop-blur-sm flex items-center justify-center p-6">
|
||||
<div className="bg-white w-full max-w-xl rounded-2xl p-8 shadow-2xl animate-in zoom-in-95 duration-300 border border-slate-100 overflow-hidden">
|
||||
<div className="flex justify-between items-center mb-8">
|
||||
<h3 className="text-xl font-black text-slate-900 uppercase tracking-tighter flex items-center gap-3">
|
||||
<Zap className="text-yellow-400 fill-yellow-400" size={24} /> 로봇 전략 설계
|
||||
</h3>
|
||||
<button onClick={() => setShowAddModal(false)} className="p-4 hover:bg-slate-100 rounded-full transition-colors"><X size={32} className="text-slate-400" /></button>
|
||||
<button onClick={() => setShowAddModal(false)} className="p-2 hover:bg-slate-100 rounded-lg transition-colors"><X size={20} className="text-slate-400" /></button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-10">
|
||||
<div className="space-y-5">
|
||||
<label className="text-[12px] font-black text-slate-400 uppercase tracking-[0.2em] ml-3">타겟 유형</label>
|
||||
<div className="flex bg-slate-100 p-2.5 rounded-[2.5rem] shadow-inner">
|
||||
<div className="space-y-6">
|
||||
<div className="space-y-3">
|
||||
<label className="text-[11px] font-black text-slate-400 uppercase tracking-widest ml-1">타겟 유형</label>
|
||||
<div className="flex bg-slate-100 p-1.5 rounded-xl shadow-inner">
|
||||
<button
|
||||
onClick={() => setTargetType('SINGLE')}
|
||||
className={`flex-1 py-5 rounded-[2rem] text-[12px] font-black transition-all ${targetType === 'SINGLE' ? 'bg-white text-slate-900 shadow-xl' : 'text-slate-400 hover:text-slate-600'}`}
|
||||
className={`flex-1 py-2.5 rounded-lg text-[12px] font-black transition-all ${targetType === 'SINGLE' ? 'bg-white text-slate-900 shadow-sm' : 'text-slate-400 hover:text-slate-600'}`}
|
||||
>
|
||||
개별 자산
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setTargetType('GROUP')}
|
||||
className={`flex-1 py-5 rounded-[2rem] text-[12px] font-black transition-all ${targetType === 'GROUP' ? 'bg-white text-slate-900 shadow-xl' : 'text-slate-400 hover:text-slate-600'}`}
|
||||
className={`flex-1 py-2.5 rounded-lg text-[12px] font-black transition-all ${targetType === 'GROUP' ? 'bg-white text-slate-900 shadow-sm' : 'text-slate-400 hover:text-slate-600'}`}
|
||||
>
|
||||
자산 그룹
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-8">
|
||||
<div className="space-y-4">
|
||||
<label className="text-[12px] font-black text-slate-400 uppercase tracking-[0.2em] ml-3">
|
||||
<div className="grid grid-cols-2 gap-6">
|
||||
<div className="space-y-3">
|
||||
<label className="text-[11px] font-black text-slate-400 uppercase tracking-widest ml-1">
|
||||
{targetType === 'SINGLE' ? '자산 선택' : '그룹 선택'}
|
||||
</label>
|
||||
{targetType === 'SINGLE' ? (
|
||||
<select
|
||||
className="w-full p-6 bg-slate-50 rounded-[2rem] border-2 border-transparent focus:border-blue-500 outline-none font-bold text-slate-800 text-base shadow-sm"
|
||||
className="w-full p-3 bg-slate-50 rounded-xl border-2 border-transparent focus:border-blue-500 outline-none font-bold text-slate-800 text-[14px] shadow-sm"
|
||||
onChange={(e) => setNewConfig({...newConfig, stockCode: e.target.value})}
|
||||
value={newConfig.stockCode || ''}
|
||||
>
|
||||
@@ -195,7 +194,7 @@ const AutoTrading: React.FC<AutoTradingProps> = ({ marketMode, stocks, configs,
|
||||
</select>
|
||||
) : (
|
||||
<select
|
||||
className="w-full p-6 bg-slate-50 rounded-[2rem] border-2 border-transparent focus:border-blue-500 outline-none font-bold text-slate-800 text-base shadow-sm"
|
||||
className="w-full p-3 bg-slate-50 rounded-xl border-2 border-transparent focus:border-blue-500 outline-none font-bold text-slate-800 text-[14px] shadow-sm"
|
||||
onChange={(e) => setNewConfig({...newConfig, groupId: e.target.value})}
|
||||
value={newConfig.groupId || ''}
|
||||
>
|
||||
@@ -204,20 +203,20 @@ const AutoTrading: React.FC<AutoTradingProps> = ({ marketMode, stocks, configs,
|
||||
</select>
|
||||
)}
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<label className="text-[12px] font-black text-slate-400 uppercase tracking-[0.2em] ml-3">단위 수량</label>
|
||||
<div className="space-y-3">
|
||||
<label className="text-[11px] font-black text-slate-400 uppercase tracking-widest ml-1">단위 수량</label>
|
||||
<input
|
||||
type="number"
|
||||
className="w-full p-6 bg-slate-50 rounded-[2rem] border-2 border-transparent focus:border-blue-500 outline-none font-black text-slate-800 text-center text-2xl shadow-sm"
|
||||
className="w-full p-3 bg-slate-50 rounded-xl border-2 border-transparent focus:border-blue-500 outline-none font-black text-slate-800 text-center text-[18px] shadow-sm"
|
||||
value={newConfig.quantity}
|
||||
onChange={(e) => setNewConfig({...newConfig, quantity: parseInt(e.target.value)})}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-5">
|
||||
<label className="text-[12px] font-black text-slate-400 uppercase tracking-[0.2em] ml-3">실행 주파수</label>
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
<div className="space-y-3">
|
||||
<label className="text-[11px] font-black text-slate-400 uppercase tracking-widest ml-1">실행 주파수</label>
|
||||
<div className="grid grid-cols-3 gap-3">
|
||||
{[
|
||||
{ val: 'DAILY', label: '매일' },
|
||||
{ val: 'WEEKLY', label: '매주' },
|
||||
@@ -226,7 +225,7 @@ const AutoTrading: React.FC<AutoTradingProps> = ({ marketMode, stocks, configs,
|
||||
<button
|
||||
key={freq.val}
|
||||
onClick={() => setNewConfig({...newConfig, frequency: freq.val as any, specificDay: freq.val === 'DAILY' ? undefined : 1})}
|
||||
className={`py-5 rounded-[2rem] text-[12px] font-black transition-all border-2 ${newConfig.frequency === freq.val ? 'bg-slate-900 text-white border-slate-900 shadow-2xl' : 'bg-white text-slate-400 border-slate-100 hover:border-slate-300'}`}
|
||||
className={`py-3 rounded-xl text-[12px] font-black transition-all border-2 ${newConfig.frequency === freq.val ? 'bg-slate-900 text-white border-slate-900 shadow-md' : 'bg-white text-slate-400 border-slate-100 hover:border-slate-300'}`}
|
||||
>
|
||||
{freq.label}
|
||||
</button>
|
||||
@@ -234,14 +233,14 @@ const AutoTrading: React.FC<AutoTradingProps> = ({ marketMode, stocks, configs,
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-8">
|
||||
<div className="grid grid-cols-2 gap-6">
|
||||
{newConfig.frequency !== 'DAILY' && (
|
||||
<div className="space-y-4">
|
||||
<label className="text-[12px] font-black text-slate-400 uppercase tracking-[0.2em] ml-3">
|
||||
<div className="space-y-3">
|
||||
<label className="text-[11px] font-black text-slate-400 uppercase tracking-widest ml-1">
|
||||
{newConfig.frequency === 'WEEKLY' ? '요일' : '날짜'}
|
||||
</label>
|
||||
<select
|
||||
className="w-full p-6 bg-slate-50 rounded-[2rem] border-2 border-transparent focus:border-blue-500 outline-none font-bold text-slate-800 shadow-sm"
|
||||
className="w-full p-3 bg-slate-50 rounded-xl border-2 border-transparent focus:border-blue-500 outline-none font-bold text-slate-800 text-[14px] shadow-sm"
|
||||
value={newConfig.specificDay}
|
||||
onChange={(e) => setNewConfig({...newConfig, specificDay: parseInt(e.target.value)})}
|
||||
>
|
||||
@@ -253,27 +252,27 @@ const AutoTrading: React.FC<AutoTradingProps> = ({ marketMode, stocks, configs,
|
||||
</select>
|
||||
</div>
|
||||
)}
|
||||
<div className="space-y-4">
|
||||
<label className="text-[12px] font-black text-slate-400 uppercase tracking-[0.2em] ml-3">시퀀스 타임</label>
|
||||
<div className="space-y-3">
|
||||
<label className="text-[11px] font-black text-slate-400 uppercase tracking-widest ml-1">시퀀스 타임</label>
|
||||
<input
|
||||
type="time"
|
||||
className="w-full p-6 bg-slate-50 rounded-[2rem] border-2 border-transparent focus:border-blue-500 outline-none font-bold text-slate-800 shadow-sm"
|
||||
className="w-full p-3 bg-slate-50 rounded-xl border-2 border-transparent focus:border-blue-500 outline-none font-bold text-slate-800 text-[14px] shadow-sm"
|
||||
value={newConfig.executionTime}
|
||||
onChange={(e) => setNewConfig({...newConfig, executionTime: e.target.value})}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-8 pt-10">
|
||||
<div className="flex gap-4 pt-6">
|
||||
<button
|
||||
onClick={() => setShowAddModal(false)}
|
||||
className="flex-1 py-6 bg-slate-100 text-slate-400 rounded-[2.5rem] font-black uppercase text-[12px] tracking-widest hover:bg-slate-200 transition-all"
|
||||
className="flex-1 py-3 bg-slate-100 text-slate-400 rounded-xl font-black uppercase text-[12px] tracking-widest hover:bg-slate-200 transition-all"
|
||||
>
|
||||
취소
|
||||
</button>
|
||||
<button
|
||||
onClick={handleAdd}
|
||||
className="flex-1 py-6 bg-blue-600 text-white rounded-[2.5rem] font-black uppercase text-[12px] tracking-widest hover:bg-blue-700 transition-all shadow-2xl shadow-blue-100"
|
||||
className="flex-1 py-3 bg-blue-600 text-white rounded-xl font-black uppercase text-[12px] tracking-widest hover:bg-blue-700 transition-all shadow-md"
|
||||
>
|
||||
전략 추가
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user