머니페니 12d235a1f1 feat: add 9 new modules - notification alerts, trading journal, position sizing, pension allocation, drawdown monitoring, benchmark dashboard, tax simulation, correlation analysis, parameter optimizer
Phase 1:
- Real-time signal alerts (Discord/Telegram webhook)
- Trading journal with entry/exit tracking
- Position sizing calculator (Fixed/Kelly/ATR)

Phase 2:
- Pension asset allocation (DC/IRP 70% risk limit)
- Drawdown monitoring with SVG gauge
- Benchmark dashboard (portfolio vs KOSPI vs deposit)

Phase 3:
- Tax benefit simulation (Korean pension tax rules)
- Correlation matrix heatmap
- Parameter optimizer with grid search + overfit detection
2026-03-29 10:03:08 +09:00

94 lines
2.8 KiB
Python

"""
Trading journal Pydantic schemas.
"""
from datetime import date, datetime
from decimal import Decimal
from typing import Optional
from enum import Enum
from pydantic import BaseModel, Field
from app.schemas.portfolio import FloatDecimal
class TradeType(str, Enum):
BUY = "buy"
SELL = "sell"
class JournalStatus(str, Enum):
OPEN = "open"
CLOSED = "closed"
class TradeJournalCreate(BaseModel):
stock_code: str = Field(..., min_length=1, max_length=20)
stock_name: Optional[str] = Field(None, max_length=100)
trade_type: TradeType
entry_price: Optional[FloatDecimal] = Field(None, gt=0)
target_price: Optional[FloatDecimal] = Field(None, gt=0)
stop_loss_price: Optional[FloatDecimal] = Field(None, gt=0)
entry_date: date
quantity: Optional[int] = Field(None, gt=0)
entry_reason: Optional[str] = None
scenario: Optional[str] = None
emotional_state: Optional[str] = None
strategy_id: Optional[int] = None
class TradeJournalUpdate(BaseModel):
stock_name: Optional[str] = Field(None, max_length=100)
exit_price: Optional[FloatDecimal] = Field(None, gt=0)
exit_date: Optional[date] = None
exit_reason: Optional[str] = None
target_price: Optional[FloatDecimal] = Field(None, gt=0)
stop_loss_price: Optional[FloatDecimal] = Field(None, gt=0)
quantity: Optional[int] = Field(None, gt=0)
lessons_learned: Optional[str] = None
emotional_state: Optional[str] = None
scenario: Optional[str] = None
entry_reason: Optional[str] = None
status: Optional[JournalStatus] = None
class TradeJournalResponse(BaseModel):
id: int
user_id: int
stock_code: str
stock_name: Optional[str] = None
trade_type: str
entry_price: Optional[FloatDecimal] = None
target_price: Optional[FloatDecimal] = None
stop_loss_price: Optional[FloatDecimal] = None
exit_price: Optional[FloatDecimal] = None
entry_date: date
exit_date: Optional[date] = None
quantity: Optional[int] = None
profit_loss: Optional[FloatDecimal] = None
profit_loss_pct: Optional[FloatDecimal] = None
entry_reason: Optional[str] = None
exit_reason: Optional[str] = None
scenario: Optional[str] = None
lessons_learned: Optional[str] = None
emotional_state: Optional[str] = None
strategy_id: Optional[int] = None
status: str
created_at: datetime
updated_at: datetime
class Config:
from_attributes = True
class TradeJournalStats(BaseModel):
total_trades: int = 0
open_trades: int = 0
closed_trades: int = 0
win_count: int = 0
loss_count: int = 0
win_rate: Optional[FloatDecimal] = None
avg_profit_loss_pct: Optional[FloatDecimal] = None
max_profit_pct: Optional[FloatDecimal] = None
max_loss_pct: Optional[FloatDecimal] = None
total_profit_loss: Optional[FloatDecimal] = None