백엔드 전체 구현 완료: 내부 서비스(Auth, Client, Realtime), API 엔드포인트 및 스케줄러 구현
This commit is contained in:
222
backend/app/db/models.py
Normal file
222
backend/app/db/models.py
Normal file
@@ -0,0 +1,222 @@
|
||||
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)
|
||||
|
||||
# -----------------
|
||||
# 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)
|
||||
Reference in New Issue
Block a user