236 lines
9.8 KiB
Python
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)
|