galaxis-po/backend/alembic/versions/59807c4e84ee_add_walkforward_results_table.py
머니페니 f818bd3290 feat: add walk-forward analysis for backtests
- Add WalkForwardResult model with train/test window metrics
- Create WalkForwardEngine that reuses existing BacktestEngine
  with rolling train/test window splits
- Add POST/GET /api/backtest/{id}/walkforward endpoints
- Add Walk-forward tab to backtest detail page with parameter
  controls, cumulative return chart, and window results table
- Add Alembic migration for walkforward_results table
- Add 8 unit tests for window generation logic (100 total passed)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 22:33:41 +09:00

46 lines
1.7 KiB
Python

"""add walkforward_results table
Revision ID: 59807c4e84ee
Revises: b7c8d9e0f1a2
Create Date: 2026-03-18 22:28:53.955519
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = '59807c4e84ee'
down_revision: Union[str, None] = 'b7c8d9e0f1a2'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('walkforward_results',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('backtest_id', sa.Integer(), nullable=False),
sa.Column('window_index', sa.Integer(), nullable=False),
sa.Column('train_start', sa.Date(), nullable=False),
sa.Column('train_end', sa.Date(), nullable=False),
sa.Column('test_start', sa.Date(), nullable=False),
sa.Column('test_end', sa.Date(), nullable=False),
sa.Column('test_return', sa.Numeric(precision=10, scale=4), nullable=True),
sa.Column('test_sharpe', sa.Numeric(precision=10, scale=4), nullable=True),
sa.Column('test_mdd', sa.Numeric(precision=10, scale=4), nullable=True),
sa.ForeignKeyConstraint(['backtest_id'], ['backtests.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_walkforward_results_id'), 'walkforward_results', ['id'], unique=False)
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f('ix_walkforward_results_id'), table_name='walkforward_results')
op.drop_table('walkforward_results')
# ### end Alembic commands ###