Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
8623b9f
[FE] SISC1-191 [CHORE] : 백테스팅 페이지에 필요한 의존성 주입
gxuoo Nov 23, 2025
4a2ed41
[FE] SISC1-191 [REMOVE] : 사용하지 않는 파일 삭제
gxuoo Nov 23, 2025
234d260
[FE] SISC1-191 [FEAT] : 조건 카드 컴포넌트 및 요소 컴포넌트 구현
gxuoo Nov 23, 2025
dfcd753
[FE] SISC1-191 [FEAT] : 규칙 카드 컴포넌트 구현
gxuoo Nov 23, 2025
9177725
[FE] SISC1-191 [FEAT] : 필드 컴포넌트 구현
gxuoo Nov 23, 2025
515bb9e
[FE] SISC1-191 [FEAT] : 규칙 카드 적용
gxuoo Nov 23, 2025
cb649a1
[FE] SISC1-191 [REFACTOR] : 노트 카드 수정
gxuoo Nov 23, 2025
ff6ea24
[FE] SISC1-191 [REFACTOR] : 전략정보 카드 수정
gxuoo Nov 23, 2025
3fdecdf
[FE] SISC1-191 [FEAT] : 주식카드 수정 및 ticker API 연결
gxuoo Nov 23, 2025
bb70f83
[FE] SISC1-191 [REFACTOR] : 백테스팅 페이지를 수정된 컴포넌트에 알맞게 수정
gxuoo Nov 23, 2025
678a758
[FE] SISC1-191 [FEAT] : 지표, 가격, 상수에 알맞게 타입을 설정해주느 메서드 구현
gxuoo Nov 23, 2025
38797cf
[FE] SISC1-191 [FEAT] : 백테스트 지표에 알맞는 mock 데이터 구현
gxuoo Nov 23, 2025
1fa1999
[FE] SISC1-191 [REFACTOR] : 기본 레이아웃 재설정
gxuoo Nov 23, 2025
d4f8ca1
[FE] SISC1-191 [FEAT] : 임시 백테스팅 결과 페이지 구현
gxuoo Nov 23, 2025
955a8b7
[FE] SISC1-191 [REFACTOR] : 백테스팅 페이지 타이틀 크기 수정
gxuoo Nov 24, 2025
d00d4fb
[FE] SISC1-191 [FEAT] : 매도 조건 카드에 기본청산기간 추가
gxuoo Nov 24, 2025
fa9fabe
[FE] SISC1-191 [REMOVE] : 중복된 의존성 제거
gxuoo Nov 24, 2025
698bb76
[FE] SISC1-191 [REMOVE] : border 색상 삭제
gxuoo Nov 24, 2025
4b0fbcf
[FE] SISC1-191 [REFACTOR] : 상태 초기값 설정
gxuoo Nov 24, 2025
b585fc2
[FE] SISC1-191 [REFACTOR] : 초기 자본값 문자열에서 숫자로 파싱
gxuoo Nov 24, 2025
6d3c859
[FE] SISC1-191 [REFACTOR] : utils 폴더에 있는 axios 파일에 있는 api 함수로 로직 수정
gxuoo Nov 24, 2025
643f5b6
[FE] SISC1-191 [FIX] : 컴포넌트 렌더링 중, 부모 컴포넌트의 상태를 바꾸는 오류 수정
gxuoo Nov 24, 2025
c4df6df
[FE] SISC1-191 [FIX] : useEffect 의존성 삭제 및 eslint 주석 추가
gxuoo Nov 24, 2025
9664a4c
[FE] SISC1-191 [FIX] : toast 대신 임시로 alert 사용
gxuoo Nov 24, 2025
441c4a0
[FE] SISC1-191 [REFACTOR] : String에서 Number로 타입 변환 처리
gxuoo Nov 24, 2025
03a8c97
[FE] SISC1-191 [REFACTOR] : 엣지 케이스 처리 보완
gxuoo Nov 24, 2025
90534da
[FE] SISC1-191 [REFACTOR] : 코드 중복 제거 및 예상치 못한 재초기화 방지
gxuoo Nov 24, 2025
70379e4
[FE] SISC1-191 [FEAT] : 주식추천목록 스타일링 추가
gxuoo Nov 24, 2025
2ab1111
[FE] SISC1-191 [FIX] : 필요없는 스타일 삭제
gxuoo Nov 24, 2025
4866d66
[FE] SISC1-191 [REFACTOR] : 매수, 매도 조건 미충족 시, alert로 알리면서 백테스트 실행 초기화
gxuoo Nov 24, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
786 changes: 783 additions & 3 deletions frontend/package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"react-day-picker": "^9.11.1",
"react-dom": "^19.1.1",
"react-router-dom": "^7.9.1",
"recharts": "^3.4.1",
"react-toastify": "^11.0.5",
"use-immer": "^0.11.0",
"uuid": "^13.0.0"
Expand Down
42 changes: 42 additions & 0 deletions frontend/src/api/backtest/useAvailableTickers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useEffect, useState } from 'react';
import { api } from '../../utils/axios';

export default function useAvailableTickers() {
const [availableTickers, setAvailableTickers] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);

useEffect(() => {
let cancelled = false;

async function fetchTickers() {
setIsLoading(true);
setError(null);

try {
const res = await api.get('/api/backtest/stocks/info');
const data = res.data;

if (!cancelled && data && Array.isArray(data.availableTickers)) {
setAvailableTickers(data.availableTickers);
}
} catch (e) {
if (!cancelled) {
setError(e);
}
} finally {
if (!cancelled) {
setIsLoading(false);
}
}
}

fetchTickers();

return () => {
cancelled = true;
};
}, []);

return { availableTickers, isLoading, error };
}
162 changes: 162 additions & 0 deletions frontend/src/api/dictionary.mock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
export async function fetchDictionary() {
// 실제 API 교체 시, 여기만 바꾸면 됩니다.
// 아래 데이터는 질문의 "예시 JSON응답 형식"을 그대로 옮긴 것입니다.
return Promise.resolve({
version: '2025-10-05',
dimensions: [
{ id: 'price', name: '가격', unit: null, range: null },
{ id: 'score_0_100', name: '스코어(0~100)', unit: null, range: [0, 100] },
{ id: 'osc_zero', name: '0선진동', unit: null, range: [-100, 100] },
{ id: 'volatility', name: '변동성', unit: null, range: null },
{ id: 'volume', name: '거래량', unit: null, range: null },
],
priceFields: [
{ code: 'Close', name: '종가', dimension: 'price' },
{ code: 'Open', name: '시가', dimension: 'price' },
{ code: 'High', name: '고가', dimension: 'price' },
{ code: 'Low', name: '저가', dimension: 'price' },
{ code: 'Volume', name: '거래량', dimension: 'volume' },
],
operators: [
{ code: 'GT', label: '>', name: '초과' },
{ code: 'GTE', label: '>=', name: '이상' },
{ code: 'LT', label: '<', name: '미만' },
{ code: 'LTE', label: '<=', name: '이하' },
{ code: 'EQ', label: '==', name: '같음' },
{ code: 'NEQ', label: '!=', name: '다름' },
{ code: 'CROSSES_ABOVE', label: '↗', name: '상향돌파' },
{ code: 'CROSSES_BELOW', label: '↘', name: '하향돌파' },
],
indicators: [
{
code: 'SMA',
name: '단순이동평균',
category: 'Trend',
dimension: 'price',
params: [
{
name: 'length',
type: 'int',
min: 2,
max: 400,
step: 1,
default: 20,
},
],
outputs: [{ name: 'value', label: '값' }],
transforms: [],
},
{
code: 'RSI',
name: 'RSI',
category: 'Momentum',
dimension: 'score_0_100',
params: [
{
name: 'length',
type: 'int',
min: 2,
max: 200,
step: 1,
default: 14,
},
],
outputs: [{ name: 'value', label: '값(0~100)' }],
transforms: [],
},
{
code: 'MACD',
name: 'MACD',
category: 'Trend',
dimension: 'osc_zero',
params: [
{ name: 'fast', type: 'int', default: 12 },
{ name: 'slow', type: 'int', default: 26 },
{ name: 'signal', type: 'int', default: 9 },
],
outputs: [
{ name: 'macd', label: 'MACD' },
{ name: 'signal', label: 'Signal' },
{ name: 'hist', label: 'Histogram' },
],
transforms: [],
},
],
dimensionCompatibility: [
{
leftDimension: 'price',
allowRightTypes: ['const', 'price', 'indicator'],
allowIndicatorDimensions: ['price'],
},
{
leftDimension: 'score_0_100',
allowRightTypes: ['const', 'indicator'],
allowIndicatorDimensions: ['score_0_100'],
},
{
leftDimension: 'osc_zero',
allowRightTypes: ['const', 'indicator'],
allowIndicatorDimensions: ['osc_zero'],
},
{
leftDimension: 'volatility',
allowRightTypes: ['const'],
allowIndicatorDimensions: [],
},
{
leftDimension: 'volume',
allowRightTypes: ['const'],
allowIndicatorDimensions: [],
},
],
dimensionAllowedOperators: [
{
dimension: 'price',
operators: [
'GT',
'GTE',
'LT',
'LTE',
'EQ',
'NEQ',
'CROSSES_ABOVE',
'CROSSES_BELOW',
],
},
{
dimension: 'score_0_100',
operators: [
'GT',
'GTE',
'LT',
'LTE',
'EQ',
'NEQ',
'CROSSES_ABOVE',
'CROSSES_BELOW',
],
},
{
dimension: 'osc_zero',
operators: [
'GT',
'GTE',
'LT',
'LTE',
'EQ',
'NEQ',
'CROSSES_ABOVE',
'CROSSES_BELOW',
],
},
{
dimension: 'volatility',
operators: ['GT', 'GTE', 'LT', 'LTE', 'EQ', 'NEQ'],
},
{
dimension: 'volume',
operators: ['GT', 'GTE', 'LT', 'LTE', 'EQ', 'NEQ'],
},
],
});
}
9 changes: 6 additions & 3 deletions frontend/src/components/Layout.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,25 @@ function Layout() {
const isRoot = location.pathname === '/';

return (
<div style={{ display: 'flex', position: 'relative' }}>
<div style={{ display: 'flex', position: 'relative', minHeight: '100vh' }}>
<Header
isRoot={isRoot}
onToggleSidebar={() => setIsSidebarOpen(!isSidebarOpen)}
style={{ position: 'fixed' }}
/>

<main
style={{
display: 'flex',
position: 'relative',
flex: 1,
marginLeft: !isRoot ? '264px' : '0',
transition: 'margin-left 0.3s ease',
}}
>
<Sidebar isOpen={isSidebarOpen} isRoot={isRoot} />
<Outlet />
<div style={{ flex: 1 }}>
<Outlet />
</div>
</main>
</div>
);
Expand Down
Loading