155 lines
5.4 KiB
TypeScript
155 lines
5.4 KiB
TypeScript
import React, { useMemo } from 'react';
|
|
import type { TrendSearchAppSettings } from '../../utils/trendSearchAppSettings';
|
|
import {
|
|
TREND_SEARCH_REFRESH_OPTIONS,
|
|
formatTrendRefreshLabel,
|
|
} from '../../utils/trendSearchAppSettings';
|
|
import TrendSearchBullishWeightsSection from './TrendSearchBullishWeightsSection';
|
|
|
|
interface Props {
|
|
settings: TrendSearchAppSettings;
|
|
onChange: (next: TrendSearchAppSettings) => void;
|
|
}
|
|
|
|
const SettingRow: React.FC<{
|
|
label: string;
|
|
desc?: string;
|
|
children: React.ReactNode;
|
|
}> = ({ label, desc, children }) => (
|
|
<div className="stg-row">
|
|
<div className="stg-row-label">
|
|
<span className="stg-row-title">{label}</span>
|
|
{desc && <span className="stg-row-desc">{desc}</span>}
|
|
</div>
|
|
<div className="stg-row-ctrl">{children}</div>
|
|
</div>
|
|
);
|
|
|
|
const SettingSection: React.FC<{ title: string; children: React.ReactNode }> = ({
|
|
title, children,
|
|
}) => (
|
|
<div className="stg-section">
|
|
<div className="stg-section-title">{title}</div>
|
|
<div className="stg-section-body">{children}</div>
|
|
</div>
|
|
);
|
|
|
|
const TrendSearchSettingsPanel: React.FC<Props> = ({ settings, onChange }) => {
|
|
const patch = (p: Partial<TrendSearchAppSettings>) => onChange({ ...settings, ...p });
|
|
|
|
const weights = useMemo(() => ({
|
|
weightMaAlignment: settings.weightMaAlignment,
|
|
weightMaSlope: settings.weightMaSlope,
|
|
weightAdxTrend: settings.weightAdxTrend,
|
|
weightMacdMomentum: settings.weightMacdMomentum,
|
|
weightPricePosition: settings.weightPricePosition,
|
|
}), [settings]);
|
|
|
|
return (
|
|
<div className="tsd-settings-panel">
|
|
<SettingSection title="상승추세 검색그룹 배점">
|
|
<TrendSearchBullishWeightsSection
|
|
variant="settings"
|
|
weights={weights}
|
|
onChange={w => patch(w)}
|
|
/>
|
|
</SettingSection>
|
|
|
|
<SettingSection title="검색 조건">
|
|
<SettingRow label="최소 합격 점수" desc="이 점수 이상인 종목만 결과에 포함됩니다.">
|
|
<input
|
|
type="number"
|
|
className="stg-input stg-input--num"
|
|
min={0}
|
|
max={100}
|
|
step={5}
|
|
value={settings.minTrendScore}
|
|
onChange={e => patch({ minTrendScore: Number(e.target.value) })}
|
|
/>
|
|
</SettingRow>
|
|
<SettingRow label="결과 목록 최대 개수" desc="스캔 후 화면에 표시할 최대 종목 수입니다.">
|
|
<input
|
|
type="number"
|
|
className="stg-input stg-input--num"
|
|
min={5}
|
|
max={50}
|
|
value={settings.limit}
|
|
onChange={e => patch({ limit: Number(e.target.value) })}
|
|
/>
|
|
</SettingRow>
|
|
<SettingRow label="스캔 대상 종목 수" desc="거래대금 상위 N종목을 평가합니다.">
|
|
<input
|
|
type="number"
|
|
className="stg-input stg-input--num"
|
|
min={20}
|
|
max={120}
|
|
value={settings.scanLimit}
|
|
onChange={e => patch({ scanLimit: Number(e.target.value) })}
|
|
/>
|
|
</SettingRow>
|
|
</SettingSection>
|
|
|
|
<SettingSection title="자동 갱신">
|
|
<SettingRow label="기본 갱신 간격" desc="추세검색 화면 자동 갱신 드롭다운의 기본값입니다.">
|
|
<select
|
|
className="stg-select"
|
|
value={settings.autoRefreshSeconds}
|
|
onChange={e => patch({ autoRefreshSeconds: Number(e.target.value) })}
|
|
>
|
|
{TREND_SEARCH_REFRESH_OPTIONS.map(sec => (
|
|
<option key={sec} value={sec}>{formatTrendRefreshLabel(sec)}</option>
|
|
))}
|
|
</select>
|
|
</SettingRow>
|
|
</SettingSection>
|
|
|
|
<SettingSection title="투자대상 자동추가">
|
|
<SettingRow
|
|
label="자동추가 사용"
|
|
desc="추세검색 갱신 후 상위 순위 종목을 가상매매 투자대상에 자동 등록합니다."
|
|
>
|
|
<label className="stg-toggle">
|
|
<input
|
|
type="checkbox"
|
|
checked={settings.autoAddTargetsEnabled}
|
|
onChange={e => patch({ autoAddTargetsEnabled: e.target.checked })}
|
|
/>
|
|
<span className="stg-toggle-slider" />
|
|
</label>
|
|
</SettingRow>
|
|
<SettingRow
|
|
label="자동추가 순위 (상위 N위)"
|
|
desc="추세점수 순위 1위부터 N위까지 자동추가 후보입니다. 투자대상 최대 개수를 초과하면 추가하지 않습니다."
|
|
>
|
|
<input
|
|
type="number"
|
|
className="stg-input stg-input--num"
|
|
min={1}
|
|
max={50}
|
|
disabled={!settings.autoAddTargetsEnabled}
|
|
value={settings.autoAddTopRank}
|
|
onChange={e => patch({ autoAddTopRank: Number(e.target.value) })}
|
|
/>
|
|
</SettingRow>
|
|
<SettingRow
|
|
label="자동추가 최소 점수"
|
|
desc="상위 순위 안에서도 추세점수가 이 값 이상인 종목만 투자대상에 자동추가합니다."
|
|
>
|
|
<input
|
|
type="number"
|
|
className="stg-input stg-input--num"
|
|
min={0}
|
|
max={100}
|
|
step={5}
|
|
disabled={!settings.autoAddTargetsEnabled}
|
|
value={settings.autoAddMinScore}
|
|
onChange={e => patch({ autoAddMinScore: Number(e.target.value) })}
|
|
/>
|
|
</SettingRow>
|
|
</SettingSection>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default TrendSearchSettingsPanel;
|