72 Commits

Author SHA1 Message Date
머니페니
b80feb7176 perf: add DB performance indexes and fix N+1 query in backtest listing
Add 10 indexes across prices, etf_prices, financials, valuations,
holdings, transactions, signals, portfolio_snapshots, and etfs tables.
Fix N+1 query in list_backtests by eager-loading backtest results
with joinedload.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 22:20:29 +09:00
머니페니
4483f6e4ba feat: add DC pension ETF-only filter to strategy API
Add dc_only parameter to all strategy endpoints. When true, filters
results to include only tickers present in the ETF table, supporting
DC pension investment constraints where only ETFs are allowed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 20:57:47 +09:00
머니페니
62ac92eaaf feat: add minimum trade amount filter to rebalancing calculation
Add min_trade_amount parameter (default 10,000 KRW) to rebalance/calculate
endpoint. Trades below this threshold are converted to hold actions to avoid
inefficient micro-trades during rebalancing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 20:57:43 +09:00
머니페니
9249821a25 feat: add realized/unrealized PnL tracking and position sizing guide
- Add realized_pnl column to transactions table with alembic migration
- Calculate realized PnL on sell transactions: (sell_price - avg_price) * quantity
- Show total realized/unrealized PnL in portfolio detail summary cards
- Show per-transaction realized PnL in transaction history table
- Add position sizing API endpoint (GET /portfolios/{id}/position-size)
- Show position sizing guide in signal execution modal for buy signals
- 8 new E2E tests, all 88 tests passing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 19:04:36 +09:00
머니페니
65618cd957 feat: add signal execution cancel with transaction rollback and holding restore 2026-03-18 18:56:29 +09:00
머니페니
213f03a8e5 fix: replace deprecated datetime.utcnow() and SQLAlchemy Query.get() 2026-03-18 18:53:29 +09:00
eb06dfc48b feat: implement scenario gap analysis - core loop completion
All checks were successful
Deploy to Production / deploy (push) Successful in 1m32s
Phase 1 (Critical):
- Add bulk rebalance apply API + UI with confirmation modal
- Add strategy results to portfolio targets flow (shared component)

Phase 2 (Important):
- Show current holdings in signal execute modal with auto-fill
- Add DC pension risk asset ratio warning (70% limit)
- Add KOSPI benchmark comparison to portfolio returns
- Track signal execution details (price, quantity, timestamp)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:18:15 +09:00
a7366d053e feat: add manual signal execution to portfolio
Allow users to execute active KJB signals by selecting a portfolio,
entering quantity and price, then creating the corresponding transaction
and updating holdings. Signal status changes to 'executed' after completion.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 16:10:48 +09:00
3c969fc53c feat: wire KJB into backtest worker, add Signal API, add scheduler job
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 15:16:13 +09:00
8d1a2f7937 feat: add DailyBacktestEngine for KJB signal-based backtesting
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 15:14:15 +09:00
65bc4cb623 feat: add KJBStrategy ranking class and API endpoint
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 15:12:18 +09:00
932b46c5fe feat: add KJBSignalGenerator for daily buy/sell signal detection
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 15:10:53 +09:00
0aac70886f feat: add TradingPortfolio for signal-based position management
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 15:08:36 +09:00
01d6b007f6 feat: add Signal Pydantic schemas
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 15:06:03 +09:00
a64636f6ff feat: add Signal model for KJB trading signals
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 15:05:17 +09:00
a33457ee6c feat: add pre-backtest data validation to detect missing price data
All checks were successful
Deploy to Production / deploy (push) Successful in 1m13s
Validates trading day count, benchmark coverage, per-date ticker
density, and date gaps before running simulation. Logs warnings for
holdings with missing prices during execution.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 22:55:50 +09:00
5422383fd8 feat: add FinancialCollector for FnGuide financial statement scraping
All checks were successful
Deploy to Production / deploy (push) Successful in 1m8s
Port make-quant-py's FnGuide scraping logic into galaxy-po's
BaseCollector pattern. Collects annual and quarterly financial
statements (revenue, net income, total assets, etc.) and maps
Korean account names to English keys for FactorCalculator.
Scheduled weekly on Monday 19:00 KST since data updates quarterly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 22:38:05 +09:00
628b431171 feat: include stock names in snapshot, transaction, and backtest transaction API responses 2026-02-16 12:50:21 +09:00
b6c22f70ae feat: add name field to SnapshotHoldingResponse, TransactionResponse, and backtest TransactionItem schemas 2026-02-16 12:49:18 +09:00
98d8c1115e feat: add backfill API endpoint for historical data collection
All checks were successful
Deploy to Production / deploy (push) Successful in 1m12s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 00:35:31 +09:00
0cd1e931b0 feat: display Korean stock names in portfolio views
All checks were successful
Deploy to Production / deploy (push) Successful in 1m35s
The portfolio API was returning only ticker symbols (e.g., "095570")
without stock names. The Stock table already has Korean names
(e.g., "AJ네트웍스") from data collection.

Backend: Add name field to HoldingWithValue schema, fetch stock names
via RebalanceService.get_stock_names() in the portfolio detail endpoint.

Frontend: Show Korean stock name as primary label with ticker as
subtitle in portfolio detail, donut charts, and target vs actual
comparison. Dashboard donut chart also shows names.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 23:22:48 +09:00
51fb812d57 fix: run data collectors in background threads to prevent server blocking
The collect endpoints were defined as async def but called synchronous
collector.run() directly, blocking the single uvicorn event loop for
up to 15+ minutes during price collection. This caused all other
requests (including auth/login) to hang, making the app unusable.

Backend: Run each collector in a daemon thread with its own DB session,
returning HTTP 200 immediately. The collector logs status to JobLog as
before, which the frontend can poll.

Frontend: Auto-poll job status every 3s while any job is "running",
with a visual indicator. Disable collect buttons during active jobs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 23:17:25 +09:00
3d5e695559 fix: resolve multiple frontend/backend bugs and add missing functionality
All checks were successful
Deploy to Production / deploy (push) Successful in 2m7s
Backend:
- Fix Decimal serialization in data_explorer.py (Decimal → FloatDecimal)
- Fix Optional type hints for query parameters in admin.py
- Fix authentication bypass in market.py search_stocks endpoint

Frontend:
- Fix 404 page: link to "/" instead of "/dashboard", proper back button
- Rewrite dashboard with real API data instead of hardcoded samples
- Implement actual equity curve and drawdown charts in backtest detail
- Remove mock data from backtest list, load real results from API
- Fix null dividend_yield display in quality strategy page
- Add skeleton loading states to 7 pages that returned null during load

Infrastructure:
- Fix PostgreSQL 18 volume mount compatibility in docker-compose.yml

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 22:49:17 +09:00
752db2ef1a fix: serialize Decimal as float in API responses and fix transaction field names
All checks were successful
Deploy to Production / deploy (push) Successful in 1m33s
Pydantic v2's model_dump(mode="json") serializes Decimal as strings (e.g.,
"33.33" instead of 33.33), causing frontend crashes when calling .toFixed()
on string values. Introduced FloatDecimal type alias with PlainSerializer
to ensure Decimal fields are serialized as floats in JSON responses.

Also fixed frontend Transaction interface to match backend field names
(created_at → executed_at, transaction_type → tx_type).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 23:47:48 +09:00
aa3e2d40d2 feat: add data explorer API for viewing collected stocks/ETFs/prices
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 23:33:11 +09:00
bffca88ce9 feat: add POST /rebalance/calculate endpoint with manual prices
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 23:30:22 +09:00
8c00359a50 feat: add rebalance calculation with manual prices and additional_buy strategy
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 23:28:40 +09:00
de77d5b2aa feat: add rebalance calculate schemas and tests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 23:27:47 +09:00
08710a6dba fix: remove nonexistent change column from price collector OHLCV mapping
All checks were successful
Deploy to Production / deploy (push) Successful in 1m10s
pykrx get_market_ohlcv returns 6 data columns (시가/고가/저가/종가/거래량/거래대금),
not 7. The 등락률 (change) column does not exist, causing a length mismatch error.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 23:27:23 +09:00
8b9fe7064c fix: correct pykrx ETF module import path and method call
All checks were successful
Deploy to Production / deploy (push) Successful in 1m42s
The pykrx library uses 'etx' not 'etf' as the module directory name,
and fetch() is the proper method that returns a DataFrame.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 21:27:41 +09:00
4261e9c777 fix: switch StockCollector and ValuationCollector from KRX CSV to pykrx
Some checks failed
Deploy to Production / deploy (push) Failing after 1m37s
KRX CSV download endpoint blocks requests from cloud/server IPs,
causing "No columns to parse from file" errors. Replaced with pykrx's
JSON-based API (get_market_ticker_list, get_market_cap_by_ticker,
get_market_fundamental_by_ticker) which is more reliable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 23:08:50 +09:00
ecb3dca571 feat: add ETF data collectors and admin API endpoints
Add ETFCollector (KRX master data) and ETFPriceCollector (pykrx OHLCV)
with corresponding admin API endpoints and frontend collection UI buttons.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 23:00:27 +09:00
72c72994b2 fix: collector error
All checks were successful
Deploy to Production / deploy (push) Successful in 1m8s
2026-02-08 22:48:35 +09:00
9f756331c4 fix: remove passlib dependency and fix FastAPI deprecation warnings
All checks were successful
Deploy to Production / deploy (push) Successful in 1m9s
- Replace passlib with direct bcrypt usage to eliminate the
  'module bcrypt has no attribute __about__' warning
- Change Query(regex=) to Query(pattern=) per FastAPI deprecation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 22:34:32 +09:00
1dae2945c3 feat: client-side password hashing and admin user auto-seeding
All checks were successful
Deploy to Production / deploy (push) Successful in 1m31s
- Hash passwords with SHA-256 on frontend before transmission to prevent
  raw password exposure in network traffic and server logs
- Switch login endpoint from OAuth2 form-data to JSON body
- Auto-create admin user on startup from ADMIN_USERNAME/ADMIN_PASSWORD
  env vars, solving login failure after registration was disabled
- Update auth tests to match new SHA-256 + JSON login flow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 22:21:36 +09:00
d6e45d01a6 feat: disable user registration endpoint
All checks were successful
Deploy to Production / deploy (push) Successful in 1m7s
Personal-use service — no new account creation needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 00:17:21 +09:00
39d2226d95 feat: production deployment setup with Gitea Actions CI/CD
Some checks failed
Deploy to Production / deploy (push) Failing after 46s
- Remove nginx from docker-compose.prod.yml (NPM handles reverse proxy)
- Add Next.js rewrites to proxy /api/* to backend (backend fully hidden)
- Bind frontend to 127.0.0.1:3000 only (NPM proxies externally)
- Replace hardcoded localhost:8000 in history page with api client
- Make CORS origins configurable via environment variable
- Restrict CORS methods to GET/POST/PUT/DELETE
- Add Gitea Actions deploy workflow with secrets-based env management
- Add security headers (X-Frame-Options, X-Content-Type-Options, Referrer-Policy)
- Add BACKEND_URL build arg to frontend Dockerfile for standalone builds

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 23:09:22 +09:00
642514b227 chore: upgrade dependencies to latest compatible versions
- Node.js: 22 → 24 (Active LTS)
- PostgreSQL: 15 → 18
- FastAPI: 0.115.6 → 0.128.2
- Uvicorn: 0.34.0 → 0.40.0
- SQLAlchemy: 2.0.36 → 2.0.46
- Alembic: 1.14.0 → 1.18.3
- Pydantic: 2.10.4 → 2.12.5
- pandas: 2.2.3 → 2.3.3
- pykrx: 1.0.45 → 1.2.3
- React: 19.2.3 → 19.2.4

Breaking changes:
- Migrate from python-jose to PyJWT for JWT handling
- numpy downgraded to 1.26.4 for pykrx compatibility

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-07 11:12:16 +09:00
d6f7d4a307 refactor: rename project from Galaxy-PO to Galaxis-Po
- Update all references in frontend, backend, and docker configs
- Update README, pyproject.toml, layout, sidebar
- Docker container names updated

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 23:24:53 +09:00
89bd8fea53 feat: add scheduler, returns calculator, and history page
- APScheduler for daily snapshots (18:30 weekdays)
- ReturnsCalculator with CAGR, TWR, MDD, volatility
- Portfolio history page with snapshots and returns tabs
- FastAPI lifespan integration for scheduler

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 12:26:16 +09:00
8842928363 feat: add PriceService and snapshot API endpoints
- PriceService: Mock implementation using DB prices
- Snapshot schemas: SnapshotListItem, ReturnsResponse, ReturnDataPoint
- Snapshot API: list, create, get, delete snapshots
- Returns API: portfolio returns calculation with CAGR

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 12:23:56 +09:00
99bd08c68a feat: add backtest API endpoints
- POST /api/backtest (create and start)
- GET /api/backtest (list)
- GET /api/backtest/{id} (detail)
- GET /api/backtest/{id}/equity-curve
- GET /api/backtest/{id}/holdings
- GET /api/backtest/{id}/transactions
- DELETE /api/backtest/{id}

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 11:51:29 +09:00
c1ee879cb4 feat: add backtest services (portfolio, engine, worker)
- VirtualPortfolio for portfolio simulation
- BacktestEngine for strategy backtesting
- Worker for async background execution

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 11:34:48 +09:00
a78c00ecbb feat: add MetricsCalculator service
- Total return, CAGR, MDD, Sharpe ratio, volatility
- Benchmark comparison metrics

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 09:37:19 +09:00
d9d9c8d772 feat: add backtest SQLAlchemy models
- Backtest, BacktestResult, BacktestEquityCurve
- BacktestHolding, BacktestTransaction

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 09:36:37 +09:00
331ab2cc56 feat: add backtest Pydantic schemas
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 09:35:53 +09:00
bc484fcb07 feat: add market data API endpoints
- GET /api/market/stocks/{ticker}
- GET /api/market/stocks/{ticker}/prices
- GET /api/market/search

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 09:01:48 +09:00
6a6ccc9c57 feat: add strategy API endpoints
- POST /api/strategy/multi-factor
- POST /api/strategy/quality
- POST /api/strategy/value-momentum

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 09:01:10 +09:00
3f8ef7e108 feat: add multi-factor, quality, and value-momentum strategies
- BaseStrategy abstract class
- MultiFactorStrategy with weighted factors
- QualityStrategy with F-Score filtering
- ValueMomentumStrategy combining value and momentum

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 08:59:05 +09:00
9eebc73390 feat: add factor calculator service
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 08:58:00 +09:00