Step by step股票分析-系統工程
設計功能(xmind):
數據處理流程(Graphviz)

頁面設置
第0頁 【版塊/熱點/技術分析/機會分析】
功能設計:
1.按不同的版塊/概念分類標準,實時統計當前各版塊/概念的狀態(漲幅/資金流動/換手/與大盤的關聯性等)
https://blog.csdn.net/hzether/article/details/146106733
https://blog.csdn.net/xiaoliouc/article/details/138266559
數據來源:
akshare獲取每日熱門趨勢板塊以及股票
https://blog.csdn.net/LML9310/article/details/135479304
衡量市場情緒

第1頁 【關注股票的技術/機會/風險分析】
功能設計:
1.根據不同的技術分析指標,自動提取符合要求的股票列表;
2.定向分析關注股票在一定期間的波動率,換手率;
3.個股在一定區間內的走勢統計,起點,低點,高點,區間波動率,區間漲幅,所在版塊及位置,與大盤的關聯度;
4.極端行情分析(超買/超賣)
超買超賣指標
隨機指標(KDJ)由 George C.Lane 創制。它綜合了動量觀念、強弱指標及移動平均線的優點,用來度量股價脫離價格正常范圍的變異程度。
KDJ指標考慮的不僅是收盤價,而且有近期的最高價和最低價,這避免了僅考慮收盤價而忽視真正波動幅度的弱點。
(一)、計算公式
公式的推導過程如下所示:
AX=當前收盤價-9天以來的最低價
BX=9天以來的最高價-9天以來的最低價
RSV=AX/BX×100
K=2/3×前一日K+1/3×RSV D=2/3×前一日D+1/3×K J=3D-2K
第一次計算時,前一日的KD皆以50代替 隨機指數以K,D,J三個符號表示。
(二)、應用原則:
1、當白色的K值在50以下的低水平,形成一底比一底高的現象,并且K值由下向上連續兩次交叉黃色的D值時,股價會產生較大的漲幅。

2、當白色的K值在50以上的高水平,形成一頂比一頂低的現象,并且K值由上向下連續兩次交叉黃色的D值時,股價會產生較大的跌幅。

3、白色的K線由下向上交叉黃色的D線失敗轉而向下探底后,K線再次向上交叉D線,兩線所夾的空間叫做向上反轉風洞。如上圖所示,當出現向上反轉風洞時股價將上漲。如下圖所示,反之叫做向下反轉風洞。出現向下反轉風洞時股價將下跌。

4、K值大于80,短期內股價容易向下出現回檔;K值小于20,短期內股價容易向上出現反彈;但在極強、極弱行情中K、D指標會在超買、超賣區內徘徊,此時應參考VR、ROC指標以確定走勢的強弱。

5、在常態行情中,D值大于80后股價經常向下回跌;D值小于20后股價易于回升。

在極端行情中,D值大于90,股價易產生瞬間回檔;D值小于15,股價易產生瞬間反彈(見下圖)。這種瞬間回檔或反彈不代表行情已經反轉。

6、J值信號不常出現,可是一旦出現,可靠性相當高。當J值大于100時,股價會形成頭部而出現回落;J值小于0時,股價會形成底部而產生反彈。

第2頁 【盯盤及預測分析】
功能設計:
1.個股與指數的收益對比


數據來源:
第3頁 【關注股票的財務分析】
功能設計:
數據來源:
1.從新浪獲取財務數據:https://zhuanlan.zhihu.com/p/639730857
經過測試,我們發現網址中的callback參數可以去除,不影響返回的數據結果,于是我們得到了所真正需要的URL:
資產負債表:https://quotes.sina.cn/cn/api/openapi.php/CompanyFinanceService.getFinanceReport2022?paperCode=sz300146&source=fzb&type=4&page=1&num=10
利潤表:https://quotes.sina.cn/cn/api/openapi.php/CompanyFinanceService.getFinanceReport2022?paperCode=sz300146&source=lrb&type=4&page=1&num=10
現金流量表:https://quotes.sina.cn/cn/api/openapi.php/CompanyFinanceService.getFinanceReport2022?paperCode=sz300146&source=llb&type=4&page=1&num=10
在瀏覽器中打開上面三個鏈接,發現返回的都是json數據:
第4頁 【投資/持倉分析】
市場情緒:
1.按不同的版塊/概念分類標準,實時統計當前各版塊/概念的狀態(漲幅/資金流動/換手/等)
https://blog.csdn.net/hzether/article/details/146106733
https://blog.csdn.net/xiaoliouc/article/details/138266559
倉位建議:
第5頁 【歷史回溯分析】
交易歷史:
勝率分析
https://tushare.pro/document/search?q=機器量化分析
持倉建議
模型評估與倉位管理:https://tushare.pro/document/1?doc_id=68
數據庫搭建
數據庫的設計思路(db_readme.md)
數據庫需要考慮以下幾個方面:
數據庫及數據表設計:包括:
- 基礎信息庫:包括股票基本信息、行業分類信息,概念分類信息(可能有不同的行業分類或概念分類標準);
- 交易數據庫:包括每年/月/周/日交易數據;
- 分時數據庫:包括每只股票在不同日的分時數據;
- K線數據庫:包括每年/月/周/日K線交易數據等;
- 財務數據庫:包括每支股票在不同時段的財務數據。
以及 - 數據表結構信息表:記錄每個數據表的結構信息,最好能依據這個表來建立相應功能的表。
- 數據表存儲信息表:用來記錄當前數據庫中所有表中已經保存的股票或代碼的信息內容,方便調用前查閱數據庫中有無相關數據記錄,如果沒有,就實時去接口拿,如果有,就直接調用。
- 數據庫變動信息表:記錄每次數據庫調用的/修改的情況。
股票實時數據引入
easyquotation 接口,提供新浪/騰訊實時報價,A股/港股
easyquotation 接口范例,點擊查看代碼
項目地址:https://github.com/shidenggui/easyquotation
代碼范例:
# -*- coding: utf-8 -*-
"""
Created on Sun Mar 9 12:15:55 2025
@author: John Cheng
https://github.com/shidenggui/easyquotation
"""
import easyquotation
import pandas as pd
#指定數據源: 新浪 ['sina'] 騰訊 ['tencent', 'qq']
quotation = easyquotation.use('sina')
# 股票單支查詢, 支持直接指定前綴,如 'sh000001'
data = quotation.real('162411')
# 多只股票查詢
data2 = quotation.real(['000001','000700'])
df = pd.DataFrame(data2)
#同時獲取指數和股票
data3 = quotation.stocks(['sh000001', 'sz000001'], prefix=True)
# prefix 參數指定返回的行情字典中的股票代碼 key 是否帶 sz/sh 前綴
data4 = quotation.market_snapshot(prefix=True)
#騰訊分時圖
quotation = easyquotation.use("timekline")
data = quotation.real(['603828'], prefix=True)
數據庫設計
用excel文件保存數據庫信息,點擊查看代碼
# -*- coding: utf-8 -*-
"""
Created on Sat Mar 15 19:13:01 2025
@author: CHENGJUN
代碼說明(感謝deepseek):
運行代碼后,會生成一個名為 stock_database_design.xlsx 的 Excel 文件,包含以下內容:
索引頁:包含所有 Sheet 的中文名和英文名。英文名帶有超鏈接,點擊可以跳轉到對應的 Sheet。列寬自適應。
數據表 Sheet:每個 Sheet 的列寬自適應,同時考慮列名和列內容的寬度,顯示清晰。
優點
代碼簡化:通過遍歷和動態生成,減少了重復代碼。
通用性增強:如果需要新增表,只需在 index_data 和 table_structures 中添加對應的信息即可。
索引頁優先:索引頁在最前面創建,方便后續動態生成數據表結構。
動態生成數據表結構:使用索引頁的英文名稱從 table_structures 字典中動態獲取表結構。
遍歷寫入 Excel 文件:使用 for 循環遍歷索引頁的英文名稱,動態寫入對應的 Sheet。
列寬自適應:遍歷每個 Sheet 的列,計算列名和列內容的最大長度,并設置列寬為 max(列名長度, 列內容長度) + 2。
超鏈接:在索引頁中為英文名添加超鏈接,點擊可以跳轉到對應的 Sheet。
"""
import pandas as pd
# 1. 創建索引頁
index_data = {
"序號": [1, 2, 3, 4, 5],
"中文名": ["股票基本信息表", "每日交易數據表", "分時數據表", "K線數據表", "數據庫變動信息表"],
"英文名": ["stock_info", "daily_trade_data", "intraday_trade_data", "kline_data", "database_change_log"]
}
df_index = pd.DataFrame(index_data)
# 2. 定義數據表結構(通過索引頁的英文名稱動態生成)
table_structures = {
"stock_info": {
"中文列名": ["股票ID", "股票代碼", "股票名稱", "市場", "行業", "上市日期"],
"英文列名": ["stock_id", "stock_code", "stock_name", "market", "industry", "listing_date"],
"數據類型": ["INT", "VARCHAR", "VARCHAR", "VARCHAR", "VARCHAR", "DATE"],
"數據長度": ["-", "10", "50", "10", "50", "-"],
"是否主鍵": ["是", "否", "否", "否", "否", "否"],
"是否外鍵": ["否", "否", "否", "否", "否", "否"],
"默認值": ["-", "-", "-", "-", "-", "-"],
"描述": ["股票的唯一標識", "股票代碼", "股票名稱", "所屬市場", "所屬行業", "股票上市日期"]
},
"daily_trade_data": {
"中文列名": ["交易ID", "股票ID", "交易日期", "開盤價", "收盤價", "最高價", "最低價", "成交量", "成交額"],
"英文列名": ["trade_id", "stock_id", "trade_date", "open_price", "close_price", "high_price", "low_price", "volume", "turnover"],
"數據類型": ["INT", "INT", "DATE", "DECIMAL", "DECIMAL", "DECIMAL", "DECIMAL", "BIGINT", "DECIMAL"],
"數據長度": ["-", "-", "-", "10,2", "10,2", "10,2", "10,2", "-", "15,2"],
"是否主鍵": ["是", "否", "否", "否", "否", "否", "否", "否", "否"],
"是否外鍵": ["否", "是", "否", "否", "否", "否", "否", "否", "否"],
"默認值": ["-", "-", "-", "-", "-", "-", "-", "-", "-"],
"描述": ["交易記錄的唯一標識", "關聯股票信息表", "交易日期", "開盤價", "收盤價", "最高價", "最低價", "成交量", "成交額"]
},
"intraday_trade_data": {
"中文列名": ["分時數據ID", "股票ID", "交易日期", "交易時間", "價格", "成交量", "成交額"],
"英文列名": ["intraday_id", "stock_id", "trade_date", "trade_time", "price", "volume", "turnover"],
"數據類型": ["INT", "INT", "DATE", "TIME", "DECIMAL", "INT", "DECIMAL"],
"數據長度": ["-", "-", "-", "-", "10,2", "-", "15,2"],
"是否主鍵": ["是", "否", "否", "否", "否", "否", "否"],
"是否外鍵": ["否", "是", "否", "否", "否", "否", "否"],
"默認值": ["-", "-", "-", "-", "-", "-", "-"],
"描述": ["分時數據的唯一標識", "關聯股票信息表", "交易日期", "交易時間", "交易價格", "成交量", "成交額"]
},
"kline_data": {
"中文列名": ["K線數據ID", "股票ID", "K線類型", "開始日期", "結束日期", "開盤價", "收盤價", "最高價", "最低價", "成交量", "成交額"],
"英文列名": ["kline_id", "stock_id", "kline_type", "start_date", "end_date", "open_price", "close_price", "high_price", "low_price", "volume", "turnover"],
"數據類型": ["INT", "INT", "VARCHAR", "DATE", "DATE", "DECIMAL", "DECIMAL", "DECIMAL", "DECIMAL", "BIGINT", "DECIMAL"],
"數據長度": ["-", "-", "10", "-", "-", "10,2", "10,2", "10,2", "10,2", "-", "15,2"],
"是否主鍵": ["是", "否", "否", "否", "否", "否", "否", "否", "否", "否", "否"],
"是否外鍵": ["否", "是", "否", "否", "否", "否", "否", "否", "否", "否", "否"],
"默認值": ["-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-"],
"描述": ["K線數據的唯一標識", "關聯股票信息表", "K線類型(日K、周K等)", "K線開始日期", "K線結束日期", "開盤價", "收盤價", "最高價", "最低價", "成交量", "成交額"]
},
"database_change_log": {
"中文列名": ["日志ID", "變更時間", "變更類型", "表名", "記錄ID", "操作用戶", "舊數據", "新數據"],
"英文列名": ["log_id", "change_time", "change_type", "table_name", "record_id", "user", "old_data", "new_data"],
"數據類型": ["INT", "TIMESTAMP", "VARCHAR", "VARCHAR", "INT", "VARCHAR", "JSON", "JSON"],
"數據長度": ["-", "-", "20", "50", "-", "50", "-", "-"],
"是否主鍵": ["是", "否", "否", "否", "否", "否", "否", "否"],
"是否外鍵": ["否", "否", "否", "否", "否", "否", "否", "否"],
"默認值": ["-", "CURRENT_TIMESTAMP", "-", "-", "-", "-", "-", "-"],
"描述": ["日志的唯一標識", "操作時間", "操作類型(INSERT/UPDATE/DELETE)", "操作的表名", "操作的記錄ID", "操作用戶", "舊數據(僅UPDATE/DELETE)", "新數據(僅INSERT/UPDATE)"]
}
}
# 3. 將字典轉換為 DataFrame
dataframes = {}
for table_name in index_data["英文名"]:
dataframes[table_name] = pd.DataFrame(table_structures[table_name])
# 4. 創建 Excel 文件
with pd.ExcelWriter("stock_database_design.xlsx", engine="xlsxwriter") as writer:
# 寫入索引頁
df_index.to_excel(writer, sheet_name="索引頁", index=False)
# 遍歷寫入其他 Sheet
for table_name, df in dataframes.items():
df.to_excel(writer, sheet_name=table_name, index=False)
# 獲取 workbook 和 worksheet 對象
workbook = writer.book
worksheet_index = writer.sheets["索引頁"]
# 為英文名添加超鏈接
for i, row in enumerate(index_data["英文名"], start=1):
worksheet_index.write_url(f"C{i + 1}", f"internal:'{row}'!A1", string=row)
# 設置所有 Sheet 的列寬為自適應
for sheet_name in writer.sheets:
worksheet = writer.sheets[sheet_name]
# 獲取當前 Sheet 的 DataFrame
if sheet_name == "索引頁":
df = df_index
else:
df = dataframes[sheet_name]
# 遍歷每一列,設置列寬
for col_num, column in enumerate(df.columns):
# 計算列名的長度
col_name_len = len(str(column))
# 計算列內容的最大長度
col_content_len = df[column].astype(str).map(len).max()
# 取最大值,并增加 2 個字符的緩沖
max_len = max(col_name_len, col_content_len) + 6
# 設置列寬
worksheet.set_column(col_num, col_num, max_len)
print("Excel 文件已生成:stock_database_design.xlsx")
數據庫結構
通過上一步生成的excel文件,反向生成SQL建表命令,實現表結構的可編輯保存和修改
根據excel文件,反向生成SQL建表命令,點擊查看代碼
# -*- coding: utf-8 -*-
"""
Created on Sat Mar 15 20:55:25 2025
@author: CHENGJUN
"""
import pandas as pd
import mysql.connector
# 讀取 Excel 文件
excel_file = "stock_database_design.xlsx"
sheets = pd.read_excel(excel_file, sheet_name=None)
# 數據庫連接配置
db_config = {
"host": "localhost",
"user": "root",
"password": "password",
"database": "stock_db"
}
# 生成 SQL 命令
sql_commands = []
for sheet_name, df in sheets.items():
if sheet_name == "索引頁":
continue # 跳過索引頁
# 提取表名
table_name = sheet_name
# 提取列信息
columns = []
for _, row in df.iterrows():
column_name = row["英文列名"]
data_type = row["數據類型"]
data_length = row["數據長度"]
is_primary_key = row["是否主鍵"] == "是"
is_foreign_key = row["是否外鍵"] == "是"
default_value = row["默認值"]
description = row["描述"] # 獲取描述信息
# 處理數據長度
if pd.isna(data_length) or data_length == "-":
column_def = f"{column_name} {data_type}"
else:
column_def = f"{column_name} {data_type}({data_length})"
# 處理主鍵
if is_primary_key:
column_def += " PRIMARY KEY"
# 處理外鍵
if is_foreign_key:
referenced_table = "stock_info" # 假設外鍵都關聯到 stock_info 表
column_def += f", FOREIGN KEY ({column_name}) REFERENCES {referenced_table}(stock_id)"
# 處理默認值
if not pd.isna(default_value) and default_value != "-":
column_def += f" DEFAULT {default_value}"
# 添加備注
if not pd.isna(description) and description != "-":
column_def += f" COMMENT '{description}'"
columns.append(column_def)
# 生成 CREATE TABLE 語句
create_table_sql = f"CREATE TABLE {table_name} (\n"
create_table_sql += ",\n".join(columns)
create_table_sql += "\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;"
sql_commands.append(create_table_sql)
# 打印生成的 SQL 命令
print("生成的 SQL 命令:")
for sql in sql_commands:
print(sql)
print("-" * 80)
# 用戶選擇是否執行 SQL 命令
execute = input("是否立即執行以上 SQL 命令?(y/n): ").strip().lower()
if execute == "y":
# 連接到數據庫
conn = mysql.connector.connect(**db_config)
cursor = conn.cursor()
# 執行 SQL 命令
for sql in sql_commands:
try:
cursor.execute(f"DROP TABLE IF EXISTS {sql.split()[2]};") # 如果表已存在,先刪除
cursor.execute(sql)
print(f"表 {sql.split()[2]} 創建成功!")
except mysql.connector.Error as err:
print(f"創建表 {sql.split()[2]} 時出錯: {err}")
# 提交更改并關閉連接
conn.commit()
cursor.close()
conn.close()
else:
print("SQL 命令未執行。")
SQL生成基礎數據庫,點擊查看代碼
-- 交易所信息表
CREATE TABLE exchange_info (
exchange_id INT PRIMARY KEY,
exchange_code VARCHAR(10) NOT NULL UNIQUE,
exchange_name VARCHAR(50) NOT NULL,
country VARCHAR(50),
timezone VARCHAR(30),
trading_hours JSON, -- 存儲交易時間段
status TINYINT DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
-- 股票基礎信息表
CREATE TABLE stock_info (
stock_id BIGINT PRIMARY KEY,
exchange_id INT,
stock_code VARCHAR(10) NOT NULL,
stock_name VARCHAR(100) NOT NULL,
listing_date DATE,
delisting_date DATE,
is_index TINYINT DEFAULT 0, -- 是否為指數
sector_code VARCHAR(20), -- 行業代碼
status TINYINT DEFAULT 1, -- 狀態:1-正常交易 2-停牌 3-退市
FOREIGN KEY (exchange_id) REFERENCES exchange_info(exchange_id),
UNIQUE KEY `idx_stock_code` (exchange_id, stock_code)
);
-- 行業分類表
CREATE TABLE sector_info (
sector_id INT PRIMARY KEY,
sector_code VARCHAR(20) NOT NULL UNIQUE,
sector_name VARCHAR(100) NOT NULL,
parent_id INT,
level TINYINT, -- 行業層級
standard VARCHAR(50) -- 分類標準(例如:證監會、申萬)
);
-- 日線數據表(按年份分區)
CREATE TABLE daily_quotes (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
stock_id BIGINT NOT NULL,
trade_date DATE NOT NULL,
open_price DECIMAL(18,4),
high_price DECIMAL(18,4),
low_price DECIMAL(18,4),
close_price DECIMAL(18,4),
adj_factor DECIMAL(18,8), -- 復權因子
volume BIGINT, -- 成交量
amount DECIMAL(20,2), -- 成交額
turnover_rate DECIMAL(10,4), -- 換手率
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY `idx_stock_date` (stock_id, trade_date),
INDEX `idx_trade_date` (trade_date)
) PARTITION BY RANGE (YEAR(trade_date)) (
PARTITION p2020 VALUES LESS THAN (2021),
PARTITION p2021 VALUES LESS THAN (2022),
PARTITION p2022 VALUES LESS THAN (2023),
PARTITION p2023 VALUES LESS THAN (2024),
PARTITION p2024 VALUES LESS THAN (2025)
);
-- 分鐘線數據表(按日期分區)
CREATE TABLE minute_quotes (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
stock_id BIGINT NOT NULL,
trade_time DATETIME NOT NULL,
open_price DECIMAL(18,4),
high_price DECIMAL(18,4),
low_price DECIMAL(18,4),
close_price DECIMAL(18,4),
volume BIGINT,
amount DECIMAL(20,2),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY `idx_stock_time` (stock_id, trade_time)
) PARTITION BY RANGE (TO_DAYS(trade_time)) (
PARTITION pmax VALUES LESS THAN MAXVALUE
);
另外一段范例:
豆包的數據庫生成代碼,點擊查看
1. 創建數據庫
首先,我們需要創建一個名為 stock_database 的數據庫:
sql
CREATE DATABASE IF NOT EXISTS stock_database;
USE stock_database;
2. 股票交易數據表
每日交易數據表(daily_trading_data)
該表用于存儲股票的每日交易數據,包括股票代碼、交易日期、開盤價、最高價、最低價、收盤價、成交量等信息。
sql
CREATE TABLE IF NOT EXISTS daily_trading_data (
id INT AUTO_INCREMENT PRIMARY KEY,
stock_code VARCHAR(20) NOT NULL,
trading_date DATE NOT NULL,
open_price DECIMAL(10, 2) NOT NULL,
high_price DECIMAL(10, 2) NOT NULL,
low_price DECIMAL(10, 2) NOT NULL,
close_price DECIMAL(10, 2) NOT NULL,
volume BIGINT NOT NULL,
UNIQUE KEY unique_stock_date (stock_code, trading_date)
);
分時交易數據表(minute_trading_data)
該表用于存儲股票的分時交易數據,與每日交易數據表類似,但時間粒度更細,精確到分鐘。
sql
CREATE TABLE IF NOT EXISTS minute_trading_data (
id INT AUTO_INCREMENT PRIMARY KEY,
stock_code VARCHAR(20) NOT NULL,
trading_time DATETIME NOT NULL,
open_price DECIMAL(10, 2) NOT NULL,
high_price DECIMAL(10, 2) NOT NULL,
low_price DECIMAL(10, 2) NOT NULL,
close_price DECIMAL(10, 2) NOT NULL,
volume BIGINT NOT NULL,
UNIQUE KEY unique_stock_time (stock_code, trading_time)
);
K 線交易數據表(k_line_trading_data)
該表用于存儲股票的 K 線交易數據,可根據不同的 K 線周期(如 5 分鐘、15 分鐘、30 分鐘等)進行存儲。
sql
CREATE TABLE IF NOT EXISTS k_line_trading_data (
id INT AUTO_INCREMENT PRIMARY KEY,
stock_code VARCHAR(20) NOT NULL,
k_line_period VARCHAR(10) NOT NULL, -- 如 '5min', '15min', '30min' 等
start_time DATETIME NOT NULL,
open_price DECIMAL(10, 2) NOT NULL,
high_price DECIMAL(10, 2) NOT NULL,
low_price DECIMAL(10, 2) NOT NULL,
close_price DECIMAL(10, 2) NOT NULL,
volume BIGINT NOT NULL,
UNIQUE KEY unique_stock_period_time (stock_code, k_line_period, start_time)
);
3. 數據庫變動信息記錄表(database_change_log)
該表用于記錄每次數據庫調用或修改的情況,包括操作類型(插入、更新、刪除等)、操作時間、操作的表名等信息。
sql
CREATE TABLE IF NOT EXISTS database_change_log (
id INT AUTO_INCREMENT PRIMARY KEY,
operation_type VARCHAR(20) NOT NULL, -- 如 'INSERT', 'UPDATE', 'DELETE'
operation_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
table_name VARCHAR(50) NOT NULL,
description TEXT
);
4. 數據表結構信息記錄表(table_structure_info)
該表用于保存不同數據表的結構信息,包括表名、字段名、字段個數、字段類型等。
sql
CREATE TABLE IF NOT EXISTS table_structure_info (
id INT AUTO_INCREMENT PRIMARY KEY,
table_name VARCHAR(50) NOT NULL,
column_name VARCHAR(50) NOT NULL,
column_position INT NOT NULL,
column_type VARCHAR(50) NOT NULL
);
5. 插入數據表結構信息示例
為了方便管理,我們可以插入各個表的結構信息到 table_structure_info 表中。以下是插入 daily_trading_data 表結構信息的示例:
sql
INSERT INTO table_structure_info (table_name, column_name, column_position, column_type)
VALUES
('daily_trading_data', 'id', 1, 'INT AUTO_INCREMENT PRIMARY KEY'),
('daily_trading_data', 'stock_code', 2, 'VARCHAR(20) NOT NULL'),
('daily_trading_data', 'trading_date', 3, 'DATE NOT NULL'),
('daily_trading_data', 'open_price', 4, 'DECIMAL(10, 2) NOT NULL'),
('daily_trading_data', 'high_price', 5, 'DECIMAL(10, 2) NOT NULL'),
('daily_trading_data', 'low_price', 6, 'DECIMAL(10, 2) NOT NULL'),
('daily_trading_data', 'close_price', 7, 'DECIMAL(10, 2) NOT NULL'),
('daily_trading_data', 'volume', 8, 'BIGINT NOT NULL');
你可以根據以上代碼創建數據庫和表結構,然后根據實際需求進行數據的插入、更新和查詢操作。同時,每次對數據庫進行操作時,可以在 database_change_log 表中記錄相應的變動信息。
數據庫關系
數據庫讀寫驗證
從Streamlit直接引用數據庫的數據:st.connection("my_database")
數據庫代碼
排除6個MySQL自帶數據庫
#排除6個MySQL自帶數據庫
sys_db = ['information_schema', 'mysql', 'performance_schema', 'sakila', 'sys', 'world']
db_list = list(set(list(sql_all.Database))-set(sys_db))
數據庫log
算法與代碼
買賣點分析

籌碼分析
參考:https://blog.csdn.net/liuhui244/article/details/145965706
指標分析
指標算法參考:https://www.gupang.com/
圖形化界面
Taipy界面(感覺比較完美)
https://docs.taipy.io/en/latest/
https://github.com/Avaiga/taipy
可以使用pip來進行安裝:pip install taipy
方案樣例:https://docs.taipy.io/en/release-4.0/tutorials/getting_started/
https://docs.taipy.io/en/release-4.0/tutorials/articles/sales_dashboard/
參考:https://github.com/Avaiga/demo-stock-visualization/blob/develop/src/main_markdown.py
Installation
Work with the demo-stock-visualization code
git clone https://github.com/Avaiga/demo-stock-visualization.git
cd demo-stock-visualization
cd src
pip install -r requirements.txt
If you want to run tests, please install Pipenv:
pip install pipenv
git clone https://github.com/Avaiga/demo-stock-visualization.git
cd demo-stock-visualization
pipenv install --dev
pipenv run pytest
繪制K線圖
matplotlib
mplfinance
官網:https://github.com/matplotlib/mplfinance
范例:https://blog.csdn.net/weixin_48964486/article/details/126711045
https://blog.csdn.net/Shepherdppz/article/details/117575286
安裝 :pip install --upgrade mplfinance
mplfinance高級交互代碼
# coding=utf-8
# inter_candle.py
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import mplfinance as mpf
# 讀取示例數據
data = pd.read_csv('test_data.csv', index_col=0)
data.index = pd.to_datetime(data.index)
my_color = mpf.make_marketcolors(up='r',
down='g',
edge='inherit',
wick='inherit',
volume='inherit')
my_style = mpf.make_mpf_style(marketcolors=my_color,
figcolor='(0.82, 0.83, 0.85)',
gridcolor='(0.82, 0.83, 0.85)')
# 定義各種字體
title_font = {'fontname': 'pingfang HK',
'size': '16',
'color': 'black',
'weight': 'bold',
'va': 'bottom',
'ha': 'center'}
large_red_font = {'fontname': 'Arial',
'size': '24',
'color': 'red',
'weight': 'bold',
'va': 'bottom'}
large_green_font = {'fontname': 'Arial',
'size': '24',
'color': 'green',
'weight': 'bold',
'va': 'bottom'}
small_red_font = {'fontname': 'Arial',
'size': '12',
'color': 'red',
'weight': 'bold',
'va': 'bottom'}
small_green_font = {'fontname': 'Arial',
'size': '12',
'color': 'green',
'weight': 'bold',
'va': 'bottom'}
normal_label_font = {'fontname': 'pingfang HK',
'size': '12',
'color': 'black',
'weight': 'normal',
'va': 'bottom',
'ha': 'right'}
normal_font = {'fontname': 'Arial',
'size': '12',
'color': 'black',
'weight': 'normal',
'va': 'bottom',
'ha': 'left'}
class InterCandle:
def __init__(self, data, my_style):
self.pressed = False
self.xpress = None
# 初始化交互式K線圖對象,歷史數據作為唯一的參數用于初始化對象
self.data = data
self.style = my_style
# 設置初始化的K線圖顯示區間起點為0,即顯示第0到第99個交易日的數據(前100個數據)
self.idx_start = 0
self.idx_range = 100
# 設置ax1圖表中顯示的均線類型
self.avg_type = 'ma'
self.indicator = 'macd'
# 初始化figure對象,在figure上建立三個Axes對象并分別設置好它們的位置和基本屬性
self.fig = mpf.figure(style=my_style, figsize=(12, 8), facecolor=(0.82, 0.83, 0.85))
fig = self.fig
self.ax1 = fig.add_axes([0.08, 0.25, 0.88, 0.60])
self.ax2 = fig.add_axes([0.08, 0.15, 0.88, 0.10], sharex=self.ax1)
self.ax2.set_ylabel('volume')
self.ax3 = fig.add_axes([0.08, 0.05, 0.88, 0.10], sharex=self.ax1)
self.ax3.set_ylabel('macd')
# 初始化figure對象,在figure上預先放置文本并設置格式,文本內容根據需要顯示的數據實時更新
self.t1 = fig.text(0.50, 0.94, '513100.SH - 納斯達克指數ETF基金', **title_font)
self.t2 = fig.text(0.12, 0.90, '開/收: ', **normal_label_font)
self.t3 = fig.text(0.14, 0.89, f'', **large_red_font)
self.t4 = fig.text(0.14, 0.86, f'', **small_red_font)
self.t5 = fig.text(0.22, 0.86, f'', **small_red_font)
self.t6 = fig.text(0.12, 0.86, f'', **normal_label_font)
self.t7 = fig.text(0.40, 0.90, '高: ', **normal_label_font)
self.t8 = fig.text(0.40, 0.90, f'', **small_red_font)
self.t9 = fig.text(0.40, 0.86, '低: ', **normal_label_font)
self.t10 = fig.text(0.40, 0.86, f'', **small_green_font)
self.t11 = fig.text(0.55, 0.90, '量(萬手): ', **normal_label_font)
self.t12 = fig.text(0.55, 0.90, f'', **normal_font)
self.t13 = fig.text(0.55, 0.86, '額(億元): ', **normal_label_font)
self.t14 = fig.text(0.55, 0.86, f'', **normal_font)
self.t15 = fig.text(0.70, 0.90, '漲停: ', **normal_label_font)
self.t16 = fig.text(0.70, 0.90, f'', **small_red_font)
self.t17 = fig.text(0.70, 0.86, '跌停: ', **normal_label_font)
self.t18 = fig.text(0.70, 0.86, f'', **small_green_font)
self.t19 = fig.text(0.85, 0.90, '均價: ', **normal_label_font)
self.t20 = fig.text(0.85, 0.90, f'', **normal_font)
self.t21 = fig.text(0.85, 0.86, '昨收: ', **normal_label_font)
self.t22 = fig.text(0.85, 0.86, f'', **normal_font)
fig.canvas.mpl_connect('button_press_event', self.on_press)
fig.canvas.mpl_connect('button_release_event', self.on_release)
fig.canvas.mpl_connect('motion_notify_event', self.on_motion)
fig.canvas.mpl_connect('key_press_event', self.on_key_press)
fig.canvas.mpl_connect('scroll_event', self.on_scroll)
def refresh_plot(self, idx_start, idx_range):
""" 根據最新的參數,重新繪制整個圖表
"""
all_data = self.data
plot_data = all_data.iloc[idx_start: idx_start + idx_range]
ap = []
# 添加K線圖重疊均線,根據均線類型添加移動均線或布林帶線
if self.avg_type == 'ma':
ap.append(mpf.make_addplot(plot_data[['MA5', 'MA10', 'MA20', 'MA60']], ax=self.ax1))
elif self.avg_type == 'bb':
ap.append(mpf.make_addplot(plot_data[['bb-u', 'bb-m', 'bb-l']], ax=self.ax1))
# 添加指標,根據指標類型添加MACD或RSI或DEMA
if self.indicator == 'macd':
ap.append(mpf.make_addplot(plot_data[['macd-m', 'macd-s']], ylabel='macd', ax=self.ax3))
bar_r = np.where(plot_data['macd-h'] > 0, plot_data['macd-h'], 0)
bar_g = np.where(plot_data['macd-h'] <= 0, plot_data['macd-h'], 0)
ap.append(mpf.make_addplot(bar_r, type='bar', color='red', ax=self.ax3))
ap.append(mpf.make_addplot(bar_g, type='bar', color='green', ax=self.ax3))
elif self.indicator == 'rsi':
ap.append(mpf.make_addplot([75] * len(plot_data), color=(0.75, 0.6, 0.6), ax=self.ax3))
ap.append(mpf.make_addplot([30] * len(plot_data), color=(0.6, 0.75, 0.6), ax=self.ax3))
ap.append(mpf.make_addplot(plot_data['rsi'], ylabel='rsi', ax=self.ax3))
else: # indicator == 'dema'
ap.append(mpf.make_addplot(plot_data['dema'], ylabel='dema', ax=self.ax3))
# 繪制圖表
mpf.plot(plot_data,
ax=self.ax1,
volume=self.ax2,
addplot=ap,
type='candle',
style=self.style,
datetime_format='%Y-%m',
xrotation=0)
plt.show()
def refresh_texts(self, display_data):
""" 更新K線圖上的價格文本
"""
# display_data是一個交易日內的所有數據,將這些數據分別填入figure對象上的文本中
self.t3.set_text(f'{np.round(display_data["open"], 3)} / {np.round(display_data["close"], 3)}')
self.t4.set_text(f'{np.round(display_data["change"], 3)}')
self.t5.set_text(f'[{np.round(display_data["pct_change"], 3)}%]')
self.t6.set_text(f'{display_data.name.date()}')
self.t8.set_text(f'{np.round(display_data["high"], 3)}')
self.t10.set_text(f'{np.round(display_data["low"], 3)}')
self.t12.set_text(f'{np.round(display_data["volume"] / 10000, 3)}')
self.t14.set_text(f'{display_data["value"]}')
self.t16.set_text(f'{np.round(display_data["upper_lim"], 3)}')
self.t18.set_text(f'{np.round(display_data["lower_lim"], 3)}')
self.t20.set_text(f'{np.round(display_data["average"], 3)}')
self.t22.set_text(f'{np.round(display_data["last_close"], 3)}')
# 根據本交易日的價格變動值確定開盤價、收盤價的顯示顏色
if display_data['change'] > 0: # 如果今日變動額大于0,即今天價格高于昨天,今天價格顯示為紅色
close_number_color = 'red'
elif display_data['change'] < 0: # 如果今日變動額小于0,即今天價格低于昨天,今天價格顯示為綠色
close_number_color = 'green'
else:
close_number_color = 'black'
self.t3.set_color(close_number_color)
self.t4.set_color(close_number_color)
self.t5.set_color(close_number_color)
def on_press(self, event):
if not (event.inaxes == self.ax1) and (not event.inaxes == self.ax3):
return
if event.button != 1:
return
self.pressed = True
self.xpress = event.xdata
# 切換當前ma類型, 在ma、bb、none之間循環
if event.inaxes == self.ax1 and event.dblclick == 1:
if self.avg_type == 'ma':
self.avg_type = 'bb'
elif self.avg_type == 'bb':
self.avg_type = 'none'
else:
self.avg_type = 'ma'
# 切換當前indicator類型,在macd/dma/rsi/kdj之間循環
if event.inaxes == self.ax3 and event.dblclick == 1:
if self.indicator == 'macd':
self.indicator = 'dma'
elif self.indicator == 'dma':
self.indicator = 'rsi'
elif self.indicator == 'rsi':
self.indicator = 'kdj'
else:
self.indicator = 'macd'
self.ax1.clear()
self.ax2.clear()
self.ax3.clear()
self.refresh_plot(self.idx_start, self.idx_range)
def on_release(self, event):
self.pressed = False
dx = int(event.xdata - self.xpress)
self.idx_start -= dx
if self.idx_start <= 0:
self.idx_start = 0
if self.idx_start >= len(self.data) - 100:
self.idx_start = len(self.data) - 100
def on_motion(self, event):
if not self.pressed:
return
if not event.inaxes == self.ax1:
return
dx = int(event.xdata - self.xpress)
new_start = self.idx_start - dx
# 設定平移的左右界限,如果平移后超出界限,則不再平移
if new_start <= 0:
new_start = 0
if new_start >= len(self.data) - 100:
new_start = len(self.data) - 100
self.ax1.clear()
self.ax2.clear()
self.ax3.clear()
self.refresh_texts(self.data.iloc[new_start])
self.refresh_plot(new_start, self.idx_range)
def on_scroll(self, event):
# 僅當鼠標滾輪在axes1范圍內滾動時起作用
scale_factor = 1.0
if event.inaxes != self.ax1:
return
if event.button == 'down':
# 縮小20%顯示范圍
scale_factor = 0.8
if event.button == 'up':
# 放大20%顯示范圍
scale_factor = 1.2
# 設置K線的顯示范圍大小
self.idx_range = int(self.idx_range * scale_factor)
# 限定可以顯示的K線圖的范圍,最少不能少于30個交易日,最大不能超過當前位置與
# K線數據總長度的差
data_length = len(self.data)
if self.idx_range >= data_length - self.idx_start:
self.idx_range = data_length - self.idx_start
if self.idx_range <= 30:
self.idx_range = 30
# 更新圖表(注意因為多了一個參數idx_range,refresh_plot函數也有所改動)
self.ax1.clear()
self.ax2.clear()
self.ax3.clear()
self.refresh_texts(self.data.iloc[self.idx_start])
self.refresh_plot(self.idx_start, self.idx_range)
# 鍵盤按下處理
def on_key_press(self, event):
data_length = len(self.data)
if event.key == 'a': # avg_type, 在ma,bb,none之間循環
if self.avg_type == 'ma':
self.avg_type = 'bb'
elif self.avg_type == 'bb':
self.avg_type = 'none'
elif self.avg_type == 'none':
self.avg_type = 'ma'
elif event.key == 'up': # 向上,看仔細1倍
if self.idx_range > 30:
self.idx_range = self.idx_range // 2
elif event.key == 'down': # 向下,看多1倍標的
if self.idx_range <= data_length - self.idx_start:
self.idx_range = self.idx_range * 2
elif event.key == 'left':
if self.idx_start > self.idx_range:
self.idx_start = self.idx_start - self.idx_range // 2
elif event.key == 'right':
if self.idx_start < data_length - self.idx_range:
self.idx_start = self.idx_start + self.idx_range //2
self.ax1.clear()
self.ax2.clear()
self.ax3.clear()
self.refresh_texts(self.data.iloc[self.idx_start])
self.refresh_plot(self.idx_start, self.idx_range)
if __name__ == '__main__':
candle = InterCandle(data, my_style)
candle.idx_start = 150
candle.idx_range = 100
candle.refresh_texts(data.iloc[249])
candle.refresh_plot(150, 100)
lightweight-charts-python
https://tradingview.github.io/lightweight-charts/
https://lightweight-charts-python.readthedocs.io/en/latest/index.html
在線示例:https://cn.tradingview.com/lightweight-charts/
TradingView 是一款非常流行的交易行情分析軟件,而 lightweight-charts 是它提供的精簡版 Js 開源庫。因為 TradingView 本身就是一款專注交易的軟件,lightweight-charts 有這高性能和用戶體驗友好的特點。
范例:https://www.poloxue.com/posts/2024-05-10-lightweight-charts-python/
KLineChart 功能非常強大,圖表也很漂亮 (但不是Python的,是Typescript語言)
https://klinecharts.com/guide/introduction
https://github.com/klinecharts/KLineChart
https://klinecharts.com/guide/quick-start.html
漂亮的范例網站:https://preview.klinecharts.com/
Typescript語言學習:https://www.runoob.com/typescript/ts-tutorial.html
運行此類代碼的沙盒:https://jsfiddle.net/
https://www.runoob.com/try/runcode.php?filename=ts-hw&type=typescript
https://codesandbox.io/p/sandbox/28pqvd?file=%2Findex.js
https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2Fklinecharts%2FKLineChart
百度pyecharts
https://github.com/pyecharts/pyecharts/
圖形參考樣式

來源:https://zhuanlan.zhihu.com/p/668340915


來源:https://zhuanlan.zhihu.com/p/671331761
風險熱圖

來源:https://zhuanlan.zhihu.com/p/673231914
必備導入庫
標準庫
NumPy ( numpy):這是 Python 中科學計算的基礎包。它提供對數組(如數學數組)的支持,以及對這些數組進行操作的數學函數的集合。
Pandas ( pandas):強大的數據操作和分析工具。在我們的例子中,以結構化且高效的方式(通過 DataFrame 對象)處理股票價格等金融數據至關重要。
Pandas 技術分析 ( pandas_ta):一個易于使用的庫,擴展了 Pandas 的技術分析功能。它幫助我們直接根據股價數據計算布林線。
SciPy是基于NumPy的用于科學計算的第三方庫。與NumPy相比,它提供了其他功能,包括scipy.stats統計分析。
數據接口庫
參考我的另一個文檔:pyhon可用在線金融數據匯總
tushare
akshare
證券寶baostock(免費)
必盈數據
https://www.biyingapi.com/
API文檔:https://ad.biyingapi.com/apidoc.html
數據分類標準:https://www.biyingapi.com/licencelt.html
算法庫
PyGAD ( pygad):這是一個用于構建遺傳算法的庫。它簡化了遺傳算法的創建和運行,我們用它來優化我們的交易策略。
PyAlgoTrade
PyAlgoTrade 是一個使用歷史數據回溯測試交易策略的 Python 庫。它允許您根據技術指標定義和測試交易策略,例如移動平均線、RSI、MACD 等。
它支持多種數據源,包括 Yahoo! 財經、Google 財經和 Alpha Vantage 等。PyAlgoTrade 提供了一個事件驅動的框架,可以輕松創建自定義交易策略。
Zipline
Zipline 是一個開源 Python 庫,用于回測交易算法。它由 Quantopian 開發,該公司提供開發和測試量化交易策略的平臺。
Zipline 提供了一個事件驅動的回測框架,允許用戶定義交易算法并根據歷史數據進行測試。它支持多種數據源,包括 CSV 文件、Pandas DataFrames 以及 Yahoo Finance 和 Quandl 等外部數據提供商。
Zipline 的主要功能之一是它允許您在真實的市場模擬中測試您的算法,包括交易成本、滑點和其他可能影響交易性能的因素。
Zipline 還提供了用于分析回測結果和可視化績效指標的工具,例如回報、回撤和風險調整績效指標。
PyPortfolioOpt
PyPortfolioOpt 是一個用于投資組合優化的 Python 庫。它提供了一系列基于預期回報、風險和多元化等因素優化投資組合的算法。它還包括用于投資組合分析和可視化的工具。
wondertrader
https://github.com/wondertrader/wtpy
其它庫
TQDM ( tqdm):在我們訓練模型時顯示進度條的庫。
tesseract-ocr解決驗證碼識別
在操作賬戶的時候有時候會跳出輸入“圖形驗證碼”窗口,上面顯示一些不規則(字符稍加扭曲變換得到的)的字符。tesseract-ocr(Optical Character Recognition)能夠掃描字符,根據字符形狀將其翻譯成電子文本的過程。因此需要安裝tesseract-ocr自動識別驗證碼。
tesseract下載地址:https://digi.bib.uni-mannheim.de/tesseract/
中國傳統智慧
sxtwl_cpp
https://pypi.org/project/sxtwl/
https://github.com/allanpk716/BaZiHelper
https://blog.csdn.net/panaimin/article/details/8544489
sxtwl_cpp是參考壽星天文歷并使用C++實現日歷庫。因為其依據天文歷法算法實現,故其可查詢范圍廣(BC722年以后與實歷相符,支持1800年以前及2200年以后的日歷查詢)。支持Android、IOS、Windows、MacOS、Linux等平臺。使用swig暴露接口給python,lua,java等語言使用。
Python API文檔自動生成工具

Docker布署
整個股票系統發布:參考文章:https://blog.csdn.net/li901101123/article/details/145656187
股票交易規則
江恩十二條
江恩十二條買賣規則是江恩經過45年在華爾街投資經驗的總結,并一直指導江恩成功的操作。
十二條買賣規則簡介如下:
1、判斷市勢,再做出買賣決定
2、在單底、雙底或三底水平線附近入市買入
3、根據市場波動的百分比買賣
4、根據三星期上升趨勢或下跌趨勢,決定買賣
5、把握市場分段波動規律
6、利用5或7點波動買賣
7、關注成交量
8、考慮時間因素
9、當出現新低或新高時買入
10、判斷大勢趨勢的轉向,決定買賣方向
11、尋找最安全的買賣點
12、發現快速市場的價位波動
炒股之成交量口訣
放量上漲,必然回調;
放量下跌,必然反彈;
縮量上漲,繼續上漲;
縮量下跌,還會下跌;
放量不漲,頂部已現;
縮量不跌,底部已見;
頂部無量下跌,后續再創新高;
頂部放量下跌,后續繼續調整。
炒股經驗談

浙公網安備 33010602011771號