Files
KisStock/backend/app/db/models.py

236 lines
9.8 KiB
Python

from datetime import datetime
from typing import List, Optional
from sqlalchemy import Integer, String, Boolean, Float, DateTime, ForeignKey, Text, JSON
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.db.database import Base
# -----------------
# 1. System & Config
# -----------------
class AiConfig(Base):
__tablename__ = "ai_configs"
id: Mapped[str] = mapped_column(String, primary_key=True)
name: Mapped[str] = mapped_column(String)
providerType: Mapped[str] = mapped_column(String) # Gemini, Ollama, OpenAI
modelName: Mapped[str] = mapped_column(String)
baseUrl: Mapped[Optional[str]] = mapped_column(String, nullable=True)
class ApiSettings(Base):
__tablename__ = "api_settings"
id: Mapped[int] = mapped_column(Integer, primary_key=True, default=1) # Always 1
# Credentials
appKey: Mapped[Optional[str]] = mapped_column(String, nullable=True)
appSecret: Mapped[Optional[str]] = mapped_column(String, nullable=True)
accountNumber: Mapped[Optional[str]] = mapped_column(String, nullable=True)
# Integrations
useTelegram: Mapped[bool] = mapped_column(Boolean, default=False)
telegramToken: Mapped[Optional[str]] = mapped_column(String, nullable=True)
telegramChatId: Mapped[Optional[str]] = mapped_column(String, nullable=True)
useNaverNews: Mapped[bool] = mapped_column(Boolean, default=False)
naverClientId: Mapped[Optional[str]] = mapped_column(String, nullable=True)
naverClientSecret: Mapped[Optional[str]] = mapped_column(String, nullable=True)
# Configs
kisApiDelayMs: Mapped[int] = mapped_column(Integer, default=250)
newsScrapIntervalMin: Mapped[int] = mapped_column(Integer, default=10)
# Token Storage (Runtime)
accessToken: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
tokenExpiry: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True)
websocketApprovalKey: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
# AI Config Relations (Foreign Keys)
preferredNewsAiId: Mapped[Optional[str]] = mapped_column(ForeignKey("ai_configs.id"), nullable=True)
preferredStockAiId: Mapped[Optional[str]] = mapped_column(ForeignKey("ai_configs.id"), nullable=True)
preferredNewsJudgementAiId: Mapped[Optional[str]] = mapped_column(ForeignKey("ai_configs.id"), nullable=True)
preferredAutoBuyAiId: Mapped[Optional[str]] = mapped_column(ForeignKey("ai_configs.id"), nullable=True)
preferredAutoSellAiId: Mapped[Optional[str]] = mapped_column(ForeignKey("ai_configs.id"), nullable=True)
# -----------------
# 2. Account & Portfolio
# -----------------
class AccountStatus(Base):
__tablename__ = "account_status"
id: Mapped[int] = mapped_column(Integer, primary_key=True, default=1)
totalAssets: Mapped[float] = mapped_column(Float, default=0.0)
buyingPower: Mapped[float] = mapped_column(Float, default=0.0)
dailyProfit: Mapped[float] = mapped_column(Float, default=0.0)
dailyProfitRate: Mapped[float] = mapped_column(Float, default=0.0)
class Holding(Base):
__tablename__ = "holdings"
stockCode: Mapped[str] = mapped_column(String, primary_key=True)
stockName: Mapped[str] = mapped_column(String)
quantity: Mapped[int] = mapped_column(Integer)
avgPrice: Mapped[float] = mapped_column(Float)
currentPrice: Mapped[float] = mapped_column(Float) # Real-time updated
profit: Mapped[float] = mapped_column(Float)
profitRate: Mapped[float] = mapped_column(Float)
marketValue: Mapped[float] = mapped_column(Float)
# -----------------
# 3. Market & Discovery
# -----------------
class MasterStock(Base):
__tablename__ = "master_stocks"
code: Mapped[str] = mapped_column(String, primary_key=True)
name: Mapped[str] = mapped_column(String)
market: Mapped[str] = mapped_column(String) # Domestic, Overseas
# Stats
per: Mapped[float] = mapped_column(Float, default=0.0)
pbr: Mapped[float] = mapped_column(Float, default=0.0)
roe: Mapped[float] = mapped_column(Float, default=0.0)
marketCap: Mapped[float] = mapped_column(Float, default=0.0)
dividendYield: Mapped[float] = mapped_column(Float, default=0.0)
# User Data
memo: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
isHidden: Mapped[bool] = mapped_column(Boolean, default=False)
class NewsCache(Base):
__tablename__ = "news_cache"
news_id: Mapped[str] = mapped_column(String, primary_key=True) # Hashed ID
title: Mapped[str] = mapped_column(Text)
description: Mapped[str] = mapped_column(Text)
link: Mapped[str] = mapped_column(Text)
pubDate: Mapped[str] = mapped_column(String)
sentiment: Mapped[Optional[str]] = mapped_column(String, nullable=True)
relatedThemes: Mapped[Optional[List]] = mapped_column(JSON, nullable=True)
relatedStocks: Mapped[Optional[List]] = mapped_column(JSON, nullable=True)
class DiscoveryRankingCache(Base):
__tablename__ = "discovery_ranking_cache"
# Composite Key simulated (category_market string or separate cols)
# Using composite PK
category: Mapped[str] = mapped_column(String, primary_key=True)
market: Mapped[str] = mapped_column(String, primary_key=True)
updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.now)
items_json: Mapped[str] = mapped_column(Text) # JSON String of StockItem[]
class StockStat(Base):
__tablename__ = "stock_stats"
code: Mapped[str] = mapped_column(String, primary_key=True)
tradingValue: Mapped[float] = mapped_column(Float, default=0.0)
buyRatio: Mapped[int] = mapped_column(Integer, default=0)
sellRatio: Mapped[int] = mapped_column(Integer, default=0)
foreignNetBuy: Mapped[int] = mapped_column(Integer, default=0)
institutionalNetBuy: Mapped[int] = mapped_column(Integer, default=0)
aiScoreBuy: Mapped[int] = mapped_column(Integer, default=0)
aiScoreSell: Mapped[int] = mapped_column(Integer, default=0)
class StockItem(Base):
__tablename__ = "stock_items"
code: Mapped[str] = mapped_column(String, primary_key=True)
name: Mapped[str] = mapped_column(String)
price: Mapped[float] = mapped_column(Float, default=0.0)
change: Mapped[float] = mapped_column(Float, default=0.0)
changePercent: Mapped[float] = mapped_column(Float, default=0.0)
market: Mapped[str] = mapped_column(String) # Domestic, Overseas
updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.now)
# -----------------
# 4. Watchlist
# -----------------
class WatchlistGroup(Base):
__tablename__ = "watchlist_groups"
id: Mapped[str] = mapped_column(String, primary_key=True)
name: Mapped[str] = mapped_column(String)
market: Mapped[str] = mapped_column(String) # Domestic, Overseas
class WatchlistItem(Base):
__tablename__ = "watchlist_items"
group_id: Mapped[str] = mapped_column(ForeignKey("watchlist_groups.id"), primary_key=True)
stock_code: Mapped[str] = mapped_column(String, primary_key=True)
added_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.now)
# -----------------
# 5. Trading & Automation
# -----------------
class TradeHistory(Base):
__tablename__ = "trade_history"
id: Mapped[str] = mapped_column(String, primary_key=True)
stockCode: Mapped[str] = mapped_column(String)
stockName: Mapped[str] = mapped_column(String)
type: Mapped[str] = mapped_column(String) # BUY, SELL
quantity: Mapped[int] = mapped_column(Integer)
price: Mapped[float] = mapped_column(Float)
timestamp: Mapped[datetime] = mapped_column(DateTime)
status: Mapped[str] = mapped_column(String) # FILLED, CANCELLED
class AutoTradeRobot(Base):
__tablename__ = "auto_trade_robots"
id: Mapped[str] = mapped_column(String, primary_key=True)
stockCode: Mapped[str] = mapped_column(String)
stockName: Mapped[str] = mapped_column(String)
groupId: Mapped[Optional[str]] = mapped_column(String, nullable=True)
type: Mapped[str] = mapped_column(String) # ACCUMULATION, TRAILING, etc.
frequency: Mapped[str] = mapped_column(String) # DAILY, WEEKLY
executionTime: Mapped[str] = mapped_column(String) # HH:MM
market: Mapped[str] = mapped_column(String)
quantity: Mapped[int] = mapped_column(Integer)
specificDay: Mapped[Optional[int]] = mapped_column(Integer, nullable=True) # 0=Monday
trailingPercent: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
active: Mapped[bool] = mapped_column(Boolean, default=True)
class ReservedOrder(Base):
__tablename__ = "reserved_orders"
id: Mapped[str] = mapped_column(String, primary_key=True)
stockCode: Mapped[str] = mapped_column(String)
stockName: Mapped[str] = mapped_column(String)
type: Mapped[str] = mapped_column(String) # BUY, SELL
market: Mapped[str] = mapped_column(String)
monitoringType: Mapped[str] = mapped_column(String) # TARGET, TRAILING
trailingType: Mapped[Optional[str]] = mapped_column(String, nullable=True) # AMOUNT, PERCENT
status: Mapped[str] = mapped_column(String) # MONITORING, TRIGGERED, EXPIRED
quantity: Mapped[int] = mapped_column(Integer)
triggerPrice: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
trailingValue: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
stopLossValue: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
highestPrice: Mapped[Optional[float]] = mapped_column(Float, nullable=True) # For Trailing
lowestPrice: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
useStopLoss: Mapped[bool] = mapped_column(Boolean, default=False)
sellAll: Mapped[bool] = mapped_column(Boolean, default=False)
stopLossType: Mapped[Optional[str]] = mapped_column(String, nullable=True)
createdAt: Mapped[datetime] = mapped_column(DateTime, default=datetime.now)
expiryDate: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True)