94 lines
2.8 KiB
Python
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
|