Ask me anything
Ithy Logo
Sign in to save

個人股票投資管理工具的開發指南

使用 PyQt6 和 SQLite 打造現代化的投資管理應用

modern stock trading dashboard

關鍵要點

  • 全面的交易記錄管理:詳細記錄每筆交易,並自動計算盈虧情況。
  • 多投資組合分析功能:支持多個投資組合,提供深入的損益分析。
  • 即時數據更新與報告生成:整合實時數據,生成多樣化的投資報告。

1. 交易記錄與管理

1.1 功能描述

交易記錄與管理是個人股票投資管理工具的核心功能。該功能允許用戶記錄每筆股票交易的詳細信息,包括股票代碼、購買價格、購買日期、數量等,並自動計算每筆交易的盈利或虧損百分比,幫助用戶實時了解投資表現。

1.2 實現方法

1.2.1 資料庫設計

使用 SQLite 數據庫來存儲交易記錄,設計一個名為 transactions 的表,包含以下字段:

CREATE TABLE transactions (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    stock_symbol TEXT NOT NULL,
    purchase_price REAL NOT NULL,
    purchase_date TEXT NOT NULL,
    quantity INTEGER NOT NULL,
    current_price REAL,
    profit_loss REAL
);
    

1.2.2 使用 PyQt6 顯示與管理交易記錄

利用 PyQt6 的 QTableWidget 或 QTableView 來顯示交易記錄,並提供一個表單讓用戶輸入交易信息。以下是一個簡單的交易記錄管理功能的代碼示例:

import sys
from PyQt6.QtWidgets import QApplication, QMainWindow, QTableWidget, QTableWidgetItem, QVBoxLayout, QWidget, QPushButton, QLineEdit, QDateEdit, QLabel
from PyQt6.QtSql import QSqlDatabase, QSqlQuery

class StockManagementApp(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("個人股票投資管理工具")
        self.setGeometry(100, 100, 800, 600)

        # 數據庫連接
        self.db = QSqlDatabase.addDatabase("QSQLITE")
        self.db.setDatabaseName("stock_management.db")
        if not self.db.open():
            print("無法連接數據庫")

        # 創建表
        query = QSqlQuery()
        query.exec("""
            CREATE TABLE IF NOT EXISTS transactions (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                stock_symbol TEXT NOT NULL,
                purchase_price REAL NOT NULL,
                purchase_date TEXT NOT NULL,
                quantity INTEGER NOT NULL
            )
        """)

        # 界面組件
        self.table = QTableWidget(self)
        self.table.setColumnCount(4)
        self.table.setHorizontalHeaderLabels(["股票代碼", "購買價格", "購買日期", "數量"])

        self.symbol_input = QLineEdit(self)
        self.price_input = QLineEdit(self)
        self.date_input = QDateEdit(self)
        self.quantity_input = QLineEdit(self)
        self.add_button = QPushButton("添加交易", self)
        self.add_button.clicked.connect(self.add_transaction)

        # 布局
        layout = QVBoxLayout()
        layout.addWidget(self.table)
        layout.addWidget(QLabel("股票代碼"))
        layout.addWidget(self.symbol_input)
        layout.addWidget(QLabel("購買價格"))
        layout.addWidget(self.price_input)
        layout.addWidget(QLabel("購買日期"))
        layout.addWidget(self.date_input)
        layout.addWidget(QLabel("數量"))
        layout.addWidget(self.quantity_input)
        layout.addWidget(self.add_button)

        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)

        # 加載數據
        self.load_data()

    def load_data(self):
        query = QSqlQuery("SELECT stock_symbol, purchase_price, purchase_date, quantity FROM transactions")
        self.table.setRowCount(0)
        while query.next():
            row = self.table.rowCount()
            self.table.insertRow(row)
            for col in range(4):
                self.table.setItem(row, col, QTableWidgetItem(str(query.value(col))))

    def add_transaction(self):
        symbol = self.symbol_input.text()
        price = float(self.price_input.text())
        date = self.date_input.date().toString("yyyy-MM-dd")
        quantity = int(self.quantity_input.text())

        query = QSqlQuery()
        query.prepare("""
            INSERT INTO transactions (stock_symbol, purchase_price, purchase_date, quantity)
            VALUES (?, ?, ?, ?)
        """)
        query.addBindValue(symbol)
        query.addBindValue(price)
        query.addBindValue(date)
        query.addBindValue(quantity)
        query.exec()

        self.load_data()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = StockManagementApp()
    window.show()
    sys.exit(app.exec())
    

1.2.3 盈利與虧損計算

定期更新當前價格,並計算每筆交易的盈利或虧損百分比。示例代碼如下:

profit_loss = (current_price - purchase_price) * quantity
profit_loss_percentage = (profit_loss / (purchase_price * quantity)) * 100
    

1.2.4 界面美化

使用 Qt Style Sheets (QSS) 美化界面,例如設置背景顏色、按鈕樣式等:

QWidget {
    background-color: #f0f0f0;
    font-family: "Segoe UI";
}
QPushButton {
    background-color: #4CAF50;
    color: white;
    border-radius: 5px;
    padding: 10px;
}
    

2. 多種投資組合分析

2.1 功能描述

多種投資組合分析功能允許用戶同時管理和分析多個投資組合,並提供詳細的損益視圖,包括未實現收益和已實現收益。這有助於用戶全面了解其投資表現,並做出更明智的投資決策。

2.2 實現方法

2.2.1 投資組合資料庫設計

在資料庫中創建一個 portfolios 表來存儲不同的投資組合信息:

CREATE TABLE portfolios (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    description TEXT
);
    

2.2.2 多投資組合管理介面

使用 QComboBox 讓用戶選擇不同的投資組合,並顯示相關的損益視圖。示例代碼如下:

self.portfolio_combobox = QComboBox(self)
self.portfolio_combobox.currentIndexChanged.connect(self.update_portfolio_view)

def update_portfolio_view(self, index):
    portfolio_id = self.get_selected_portfolio_id(index)
    # 根據 portfolio_id 加載相關數據並更新視圖
    

2.2.3 損益計算與視覺化

計算每個投資組合的未實現收益和已實現收益,並使用 QChart 或 Matplotlib 繪製收益趨勢圖:

import matplotlib.pyplot as plt

def plot_profit_loss(self, data):
    dates = [item['date'] for item in data]
    profit = [item['profit'] for item in data]
    plt.plot(dates, profit, marker='o')
    plt.title('收益趨勢圖')
    plt.xlabel('日期')
    plt.ylabel('收益')
    plt.show()
    

2.2.4 表格與圖表的整合

使用 QTableView 展示詳細的交易數據,同時在旁邊顯示圖表,以便用戶直觀地看到投資表現。


3. 即時數據與報告

3.1 功能描述

即時數據與報告功能提供最新的投資數據,並生成多樣化的報告。這包括與金融賬戶同步、實時更新股票價格、以及生成月報或年報,讓用戶隨時掌握其資產狀況。

3.2 實現方法

3.2.1 整合實時數據 API

使用第三方 API(如 Yahoo Finance 或 Alpha Vantage)獲取即時股票數據。示例代碼如下:

import yfinance as yf

def get_latest_price(symbol):
    ticker = yf.Ticker(symbol)
    data = ticker.history(period="1d")
    latest_price = data['Close'][-1]
    return latest_price
    

3.2.2 定期更新數據庫

設置定時任務,定期更新數據庫中的 current_price 字段,並重新計算盈虧百分比:

import schedule
import time

def update_prices():
    query = QSqlQuery("SELECT id, stock_symbol, purchase_price, quantity FROM transactions")
    while query.next():
        id = query.value(0)
        symbol = query.value(1)
        purchase_price = query.value(2)
        quantity = query.value(3)
        current_price = get_latest_price(symbol)
        profit_loss = (current_price - purchase_price) * quantity
        profit_loss_percentage = (profit_loss / (purchase_price * quantity)) * 100
        update_query = QSqlQuery()
        update_query.prepare("""
            UPDATE transactions
            SET current_price = ?, profit_loss = ?
            WHERE id = ?
        """)
        update_query.addBindValue(current_price)
        update_query.addBindValue(profit_loss_percentage)
        update_query.addBindValue(id)
        update_query.exec()

schedule.every().day.at("18:00").do(update_prices)

while True:
    schedule.run_pending()
    time.sleep(1)
    

3.2.3 報告生成

使用 pandas 和 reportlab 庫來生成 CSV 或 PDF 格式的報告:

import pandas as pd
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas

def generate_report():
    query = QSqlQuery("SELECT * FROM transactions")
    data = []
    while query.next():
        data.append({
            'symbol': query.value('stock_symbol'),
            'purchase_price': query.value('purchase_price'),
            'current_price': query.value('current_price'),
            'quantity': query.value('quantity'),
            'profit_loss': query.value('profit_loss')
        })
    df = pd.DataFrame(data)
    df.to_csv('report.csv', index=False)
    
    # 生成 PDF 報告
    c = canvas.Canvas("report.pdf", pagesize=letter)
    c.drawString(100, 750, "個人股票投資報告")
    # 添加更多內容
    c.save()
    

4. 多樣化的投資選擇

4.1 功能描述

多樣化的投資選擇允許用戶追蹤多種資產類型,包括股票、債券、加密貨幣等,並提供市場監控和投資組合優化功能,幫助用戶制定更有效的投資策略。

4.2 實現方法

4.2.1 擴展資料庫結構

在 transactions 表中增加 asset_type 字段來區分不同的資產類型:

ALTER TABLE transactions ADD COLUMN asset_type TEXT;
    

4.2.2 多資產類型管理介面

使用 QTabWidget 創建多個頁面,分別顯示不同資產的投資情況。例如,股票、債券、加密貨幣等各有一個頁籤:

self.tab_widget = QTabWidget()
self.tab_widget.addTab(StocksTab(), "股票")
self.tab_widget.addTab(BondsTab(), "債券")
self.tab_widget.addTab(CryptoTab(), "加密貨幣")
layout.addWidget(self.tab_widget)
    

4.2.3 市場監控功能

顯示各類資產的實時價格和趨勢圖,幫助用戶追蹤市場動態。以下是一個簡單的實現範例:

def display_market_trends(asset_type):
    symbols = get_symbols_by_asset_type(asset_type)
    prices = [get_latest_price(symbol) for symbol in symbols]
    plt.bar(symbols, prices)
    plt.title(f"{asset_type} 市場價格")
    plt.xlabel("符號")
    plt.ylabel("價格")
    plt.show()
    

5. 現代化使用者介面設計

5.1 設計建議

為了提供現代化且優美的使用者介面,應該採用以下設計建議:

  • 使用 QSS 美化界面,設置一致的色彩方案和字體風格。
  • 利用 QMainWindow 創建主窗口,包含菜單欄、工具欄和狀態欄,提供易用的導航和操作介面。
  • 使用 QStackedWidget 實現多頁面切換功能,保持介面的整潔和一致。

5.2 界面佈局與導航

設計一個直觀的界面佈局,使用頂部工具欄和側邊導航欄來切換不同的功能模塊。以下是一個簡單的主窗口佈局代碼示例:

from PyQt6.QtWidgets import QMainWindow, QToolBar, QAction, QTabWidget, QWidget, QVBoxLayout

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("個人股票投資管理系統")
        self.resize(1200, 800)

        # 建立頂部工具列
        toolbar = QToolBar()
        self.addToolBar(toolbar)

        # 新增功能按鈕
        add_transaction_btn = QAction("新增交易", self)
        portfolio_analysis_btn = QAction("投資組合分析", self)
        reports_btn = QAction("報表匯出", self)

        toolbar.addAction(add_transaction_btn)
        toolbar.addAction(portfolio_analysis_btn)
        toolbar.addAction(reports_btn)

        # 建立分頁介面
        self.tab_widget = QTabWidget()
        self.setCentralWidget(self.tab_widget)

        # 新增各功能分頁
        self.positions_tab = PositionsTab()
        self.transactions_tab = TransactionsTab()
        self.analysis_tab = AnalysisTab()

        self.tab_widget.addTab(self.positions_tab, "持股部位")
        self.tab_widget.addTab(self.transactions_tab, "交易記錄")
        self.tab_widget.addTab(self.analysis_tab, "績效分析")
    

5.3 視覺效果與用戶體驗

使用現代化的色彩搭配和排版,提升用戶體驗。例如,採用深色主題來減少長時間使用的眼睛疲勞:

QWidget {
    background-color: #2e2e2e;
    color: #ffffff;
    font-family: "Arial";
}
QPushButton {
    background-color: #388278;
    color: white;
    border-radius: 5px;
    padding: 10px;
}
    

6. 數據庫連接與管理

6.1 實現方法

6.1.1 連接 SQLite 數據庫

使用 PyQt6 的 QSqlDatabase 連接 SQLite 數據庫,並處理連接失敗的情況:

from PyQt6.QtSql import QSqlDatabase, QSqlQuery

def connect_database():
    db = QSqlDatabase.addDatabase("QSQLITE")
    db.setDatabaseName("stock_portfolio.db")
    if not db.open():
        print("無法連接數據庫")
        return False
    return True
    

6.1.2 數據庫模型與界面組件綁定

使用 QSqlTableModel 或 QSqlQueryModel 將數據庫中的數據與界面組件(如表格視圖)進行綁定,實現數據的動態顯示與更新:

from PyQt6.QtSql import QSqlTableModel

class TransactionsTab(QWidget):
    def __init__(self):
        super().__init__()
        layout = QVBoxLayout(self)

        self.table_view = QTableView()
        self.model = QSqlTableModel()
        self.model.setTable("transactions")
        self.model.select()

        self.model.setHeaderData(1, Qt.Horizontal, "股票代號")
        self.model.setHeaderData(2, Qt.Horizontal, "交易類型")
        self.model.setHeaderData(3, Qt.Horizontal, "價格")
        self.model.setHeaderData(4, Qt.Horizontal, "數量")
        self.model.setHeaderData(5, Qt.Horizontal, "交易日期")

        self.table_view.setModel(self.model)
        layout.addWidget(self.table_view)
    

7. 完整代碼示例

7.1 主應用程式結構

以下是一個綜合性較強的應用程式結構示例,包括數據庫連接、界面設計和主要功能模塊:

import sys
from PyQt6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QLabel, QTableWidget, QTableWidgetItem, QPushButton, QComboBox, QTabWidget, QWidget
from PyQt6.QtSql import QSqlDatabase, QSqlQuery
import yfinance as yf
import matplotlib.pyplot as plt

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("個人股票投資管理工具")
        self.setGeometry(100, 100, 1200, 800)

        # 數據庫連接
        self.db = QSqlDatabase.addDatabase("QSQLITE")
        self.db.setDatabaseName("stock_portfolio.db")
        if not self.db.open():
            print("無法連接數據庫")
            sys.exit(1)

        # 創建表
        self.create_tables()

        # 建立主要佈局
        main_widget = QWidget()
        self.setCentralWidget(main_widget)
        layout = QVBoxLayout(main_widget)

        # 建立頂部工具列
        toolbar = QToolBar()
        self.addToolBar(toolbar)

        add_transaction_btn = QAction("新增交易", self)
        portfolio_analysis_btn = QAction("投資組合分析", self)
        reports_btn = QAction("報表匯出", self)

        toolbar.addAction(add_transaction_btn)
        toolbar.addAction(portfolio_analysis_btn)
        toolbar.addAction(reports_btn)

        # 建立分頁介面
        self.tab_widget = QTabWidget()
        layout.addWidget(self.tab_widget)

        # 新增各功能分頁
        self.positions_tab = PositionsTab()
        self.transactions_tab = TransactionsTab()
        self.analysis_tab = AnalysisTab()

        self.tab_widget.addTab(self.positions_tab, "持股部位")
        self.tab_widget.addTab(self.transactions_tab, "交易記錄")
        self.tab_widget.addTab(self.analysis_tab, "績效分析")

    def create_tables(self):
        query = QSqlQuery()
        query.exec("""
            CREATE TABLE IF NOT EXISTS stocks (
                symbol TEXT PRIMARY KEY,
                name TEXT,
                market TEXT,
                category TEXT
            )
        """)
        query.exec("""
            CREATE TABLE IF NOT EXISTS transactions (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                stock_symbol TEXT,
                trade_type TEXT,
                price REAL,
                shares INTEGER,
                trade_date DATE,
                commission REAL,
                notes TEXT,
                asset_type TEXT,
                FOREIGN KEY (stock_symbol) REFERENCES stocks(symbol)
            )
        """)
        query.exec("""
            CREATE TABLE IF NOT EXISTS portfolios (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                name TEXT,
                description TEXT
            )
        """)

class TransactionsTab(QWidget):
    def __init__(self):
        super().__init__()
        layout = QVBoxLayout(self)

        # 交易記錄表格
        self.table = QTableView()
        self.model = QSqlTableModel()
        self.model.setTable("transactions")
        self.model.select()

        # 設定表格欄位
        self.model.setHeaderData(1, Qt.Horizontal, "股票代號")
        self.model.setHeaderData(2, Qt.Horizontal, "交易類型")
        self.model.setHeaderData(3, Qt.Horizontal, "價格")
        self.model.setHeaderData(4, Qt.Horizontal, "數量")
        self.model.setHeaderData(5, Qt.Horizontal, "交易日期")

        self.table.setModel(self.model)
        layout.addWidget(self.table)

class AnalysisTab(QWidget):
    def __init__(self):
        super().__init__()
        layout = QVBoxLayout(self)

        # 圖表區域
        self.chart_view = QLabel("此處顯示績效圖表")
        layout.addWidget(self.chart_view)

        # 統計數據區域
        stats_group = QGroupBox("投資統計")
        stats_layout = QGridLayout()

        self.total_value_label = QLabel("總市值: ")
        self.profit_loss_label = QLabel("未實現損益: ")
        self.return_rate_label = QLabel("報酬率: ")

        stats_layout.addWidget(self.total_value_label, 0, 0)
        stats_layout.addWidget(self.profit_loss_label, 0, 1)
        stats_layout.addWidget(self.return_rate_label, 0, 2)

        stats_group.setLayout(stats_layout)
        layout.addWidget(stats_group)

class PositionsTab(QWidget):
    def __init__(self):
        super().__init__()
        layout = QVBoxLayout(self)
        self.label = QLabel("持股部位詳情")
        layout.addWidget(self.label)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec())
    

8. 結論

利用 PyQt6 和 SQLite 可以輕鬆開發一款功能全面且現代化的個人股票投資管理工具。通過詳細的交易記錄管理、多投資組合分析、即時數據更新與報告生成以及多樣化的投資選擇,能夠滿足用戶對於投資管理的多方面需求。此外,通過應用現代化的使用者介面設計,提供良好的用戶體驗,讓投資管理變得更加高效和愉悅。未來可以進一步擴展功能,如加入警示系統、更多圖表分析等,提升應用的實用性和競爭力。


參考資料


Last updated January 22, 2025

AI-assisted research. Sources, methodology and corrections · Source-checked guides and tools · Explore published answers

Ask Ithy AI