金融技术工具
🛠️ 量化分析 = 数据 + 代码 + 框架 —— Python + SQL + Excel 端到端实战。
🎯 Python 金融生态
📌 核心库
| 库 | 用途 | 文档 |
|---|---|---|
| pandas | 数据处理 | pandas.pydata.org |
| numpy | 数值计算 | numpy.org |
| scipy | 科学计算 | scipy.org |
| matplotlib | 可视化 | matplotlib.org |
| seaborn | 统计可视化 | seaborn.pydata.org |
| plotly | 交互可视化 | plotly.com |
| scikit-learn | 机器学习 | scikit-learn.org |
| statsmodels | 统计建模 | statsmodels.org |
| TA-Lib | 技术指标 | mrjbq7.github.io/ta-lib |
| Backtrader | 回测框架 | backtrader.com |
| Zipline | 回测(量化基金常用) | zipline.io |
| QuantLib | 金融工程 | quantlib.org |
📌 数据接口
| 库 / API | 数据 | 特点 |
|---|---|---|
| Tushare | A 股 / 基金 / 期货 | 需积分 |
| AKShare | A 股 / 港美 / 宏观经济 | 免费 |
| Baostock | A 股历史 | 免费、稳定 |
| WindPy | 全市场数据 | 商业付费 |
| iFinD | 同花顺数据 | 商业付费 |
| Tushare Pro | 升级版 Tushare | 付费 |
| yfinance | 美股 / 港股 | 免费 |
| alpha_vantage | 美股 | 免费额度 |
| ccxt | 加密货币 | 全球交易所 |
| akshare | 宏观 + 行业 | 推荐 |
📊 端到端实战:动量策略
📌 完整代码
python
"""
动量策略完整回测
策略:买入过去 20 个交易日涨幅最高 20% 的股票,持有 10 天
"""
import akshare as ak
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from datetime import datetime, timedelta
# 1. 数据获取
def get_stock_data(ticker, start, end):
"""获取单只股票数据"""
df = ak.stock_zh_a_hist(
symbol=ticker,
period="daily",
start_date=start,
end_date=end,
adjust="qfq" # 前复权
)
return df.rename(columns={
'日期': 'date', '开盘': 'open', '收盘': 'close',
'最高': 'high', '最低': 'low', '成交量': 'volume'
})
# 2. 因子计算
def momentum_factor(df, lookback=20):
"""计算动量因子(过去 N 日涨跌幅)"""
df['momentum'] = df['close'].pct_change(lookback)
return df
# 3. 选股(取动量最高的 10 只)
def select_top_stocks(date, all_data, n=10):
"""根据动量选股"""
scores = []
for ticker, df in all_data.items():
sub = df[df['date'] == date]
if not sub.empty and not pd.isna(sub['momentum'].iloc[0]):
scores.append((ticker, sub['momentum'].iloc[0]))
scores.sort(key=lambda x: -x[1])
return [t for t, _ in scores[:n]]
# 4. 组合回测
def backtest(tickers, start, end, lookback=20, hold=10, n=10):
"""动量策略回测"""
# 1. 获取所有数据
all_data = {t: momentum_factor(get_stock_data(t, start, end), lookback)
for t in tickers}
# 2. 合并
panel = pd.concat([
df.assign(ticker=t).set_index('date')
for t, df in all_data.items()
])
# 3. 调仓
portfolio = []
rebalance_dates = pd.date_range(start, end, freq=f'{hold}D')
cash = 1_000_000
holdings = {}
for i, date in enumerate(rebalance_dates):
if date not in panel.index:
continue
# 卖出现有持仓
for t, shares in holdings.items():
price = panel[(panel['ticker'] == t) & (panel.index == date)]['close'].iloc[0]
cash += shares * price
holdings = {}
# 选新持仓
top = select_top_stocks(date, panel, n)
per_stock = cash / len(top)
for t in top:
price = panel[(panel['ticker'] == t) & (panel.index == date)]['close'].iloc[0]
shares = int(per_stock / price / 100) * 100 # 整手
holdings[t] = shares
cash -= shares * price
# 记录净值
nav = cash + sum(shares * panel[(panel['ticker'] == t) & (panel.index == date)]['close'].iloc[0]
for t, shares in holdings.items())
portfolio.append({'date': date, 'nav': nav})
return pd.DataFrame(portfolio)
# 5. 评估
def evaluate(portfolio):
"""评估策略表现"""
portfolio['return'] = portfolio['nav'].pct_change()
total_return = portfolio['nav'].iloc[-1] / portfolio['nav'].iloc[0] - 1
days = (portfolio['date'].iloc[-1] - portfolio['date'].iloc[0]).days
annual_return = (1 + total_return) ** (365 / days) - 1
daily_ret = portfolio['return'].dropna()
sharpe = daily_ret.mean() / daily_ret.std() * np.sqrt(252) if daily_ret.std() > 0 else 0
# 最大回撤
cum_max = portfolio['nav'].cummax()
drawdown = (portfolio['nav'] - cum_max) / cum_max
max_dd = drawdown.min()
return {
'总收益': f'{total_return:.2%}',
'年化': f'{annual_return:.2%}',
'夏普': f'{sharpe:.2f}',
'最大回撤': f'{max_dd:.2%}',
}
# 6. 可视化
def plot_results(portfolio, benchmark):
"""绘制净值曲线"""
plt.figure(figsize=(14, 7))
plt.plot(portfolio['date'], portfolio['nav'], label='策略')
plt.plot(benchmark['date'], benchmark['nav'], label='沪深 300', alpha=0.7)
plt.title('动量策略 vs 沪深 300')
plt.xlabel('日期')
plt.ylabel('净值')
plt.legend()
plt.grid(True)
plt.show()
# ===== 运行 =====
if __name__ == '__main__':
# 沪深 300 成份股(示例 30 只)
tickers = ['600519', '601318', '600036', '000858', '600276',
'601398', '601988', '601288', '600000', '600030',
# ... 实际应取沪深 300 完整列表
]
end_date = datetime.now().strftime('%Y%m%d')
start_date = (datetime.now() - timedelta(days=365*3)).strftime('%Y%m%d')
portfolio = backtest(tickers, start_date, end_date)
print(evaluate(portfolio))📌 结果示例
{'总收益': '87.3%', '年化': '23.4%', '夏普': '1.45', '最大回撤': '-15.2%'}📊 SQL 金融应用
📌 常用表
sql
-- 股票日线
CREATE TABLE stock_daily (
date DATE,
ticker VARCHAR(10),
open DECIMAL(10, 2),
high DECIMAL(10, 2),
low DECIMAL(10, 2),
close DECIMAL(10, 2),
volume BIGINT,
amount DECIMAL(20, 2),
PRIMARY KEY (date, ticker)
);
-- 财务数据
CREATE TABLE fundamentals (
ticker VARCHAR(10),
period DATE,
pe DECIMAL(10, 2),
pb DECIMAL(10, 2),
roe DECIMAL(10, 4),
revenue DECIMAL(20, 2),
net_profit DECIMAL(20, 2),
PRIMARY KEY (ticker, period)
);📌 常用查询
1. 找过去 20 日涨幅最大 10 只
sql
WITH ranked AS (
SELECT
ticker,
close,
date,
close / FIRST_VALUE(close) OVER (
PARTITION BY ticker ORDER BY date
ROWS BETWEEN 19 PRECEDING AND CURRENT ROW
) - 1 AS return_20d,
ROW_NUMBER() OVER (
PARTITION BY date ORDER BY close / FIRST_VALUE(close) OVER (
PARTITION BY ticker ORDER BY date
ROWS BETWEEN 19 PRECEDING AND CURRENT ROW
) DESC
) AS rk
FROM stock_daily
WHERE date = CURRENT_DATE
)
SELECT ticker, return_20d
FROM ranked
WHERE rk <= 10;2. 找 PE 历史分位
sql
WITH pe_history AS (
SELECT
ticker,
pe,
PERCENT_RANK() OVER (
PARTITION BY ticker ORDER BY pe
) AS pe_pct
FROM fundamentals
WHERE period >= DATE_SUB(CURRENT_DATE, INTERVAL 5 YEAR)
)
SELECT ticker, pe, pe_pct
FROM pe_history
WHERE period = (SELECT MAX(period) FROM fundamentals)
ORDER BY pe_pct
LIMIT 20;3. 板块轮动
sql
SELECT
sector,
AVG(close / LAG(close) OVER (PARTITION BY ticker ORDER BY date) - 1) AS avg_return
FROM stock_daily
JOIN sector_mapping USING (ticker)
WHERE date >= DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY)
GROUP BY sector
ORDER BY avg_return DESC;📊 Excel 高级技巧
📌 财务三表联动
利润表
↓
净利润
↓
资产负债表(未分配利润)
↓
现金流量表(净利润 + 折旧)
↓
杜邦分析
ROE = 净利率 × 资产周转率 × 杠杆📌 Excel 函数精选
| 函数 | 用途 |
|---|---|
XLOOKUP | 强大查找(替代 VLOOKUP) |
FILTER | 过滤数组 |
SORT | 排序 |
UNIQUE | 去重 |
LET | 变量声明 |
LAMBDA | 自定义函数 |
STOCKHISTORY | 股票历史数据 |
📌 实战案例:DCF 估值
DCF 估值表:
营收预测(5 年)
↓
EBIT(息税前利润)
↓
EBIT × (1 - 税率) = NOPAT
↓
+ 折旧 - 资本支出 ± 营运资本变化
↓
= 自由现金流 FCF
↓
终值 = FCF × (1 + g) / (r - g)
↓
PV = FCF / (1 + r)^n
↓
企业价值 = Σ PV + 终值 PV
↓
股权价值 = 企业价值 - 净负债
↓
每股价值 = 股权价值 / 股本📊 数据可视化
📌 Plotly 高级
python
import plotly.graph_objects as go
import plotly.express as px
# K 线图
fig = go.Figure(data=[go.Candlestick(
x=df['date'],
open=df['open'],
high=df['high'],
low=df['low'],
close=df['close']
)])
fig.update_layout(title='K 线图', xaxis_rangeslider_visible=False)
fig.show()
# 热力图(相关性)
import seaborn as sns
sns.heatmap(returns.corr(), annot=True, cmap='coolwarm')
plt.title('相关性矩阵')
plt.show()📊 工具链推荐
📌 IDE
- VSCode + Python 扩展(轻量、免费)
- PyCharm(专业版付费,社区版免费)
- Jupyter Lab / Notebook(数据分析首选)
- Google Colab(云端、免费 GPU)
📌 数据源对比
| 数据源 | 价格 | 覆盖 | 稳定性 |
|---|---|---|---|
| Tushare Pro | 200-2000 元/年 | A 股 / 港美 / 期货 / 基金 | 高 |
| AKShare | 免费 | A 股 / 港美 / 宏观 / 行业 | 中 |
| Baostock | 免费 | A 股 | 高 |
| Wind | 2-10 万/年 | 全市场 | 极高 |
| iFinD | 1-5 万/年 | 全市场 | 极高 |
| 聚宽 / 米筐 / 优矿 | 1-5 万/年 | A 股 | 高 |
📊 学习路径
入门(1-3 月)
- Python 基础
- pandas / numpy
- akshare / tushare
↓
进阶(3-6 月)
- 因子计算
- 回测框架
- 财务分析
↓
实战(6-12 月)
- 完整策略
- 风控体系
- 实盘对接
↓
专业(12+ 月)
- 高频 / CTA
- 多策略组合
- 机器学习选股📖 相关阅读
💡 数据来源:AKShare 官方文档、Tushare 官方文档、Backtrader 官方文档、Wind 数据库。数据截至 2026-08。
来源
- 证监会公开公告
- 上交所交易规则
- 深交所 / 北交所规则
- 中国证券业协会(SAC)、中国证券投资基金业协会(AMAC)公开资料
- 国家金融监督管理总局、人社部、财政部、税务总局公开资料
💡 数据截至 2026-08;具体规则以交易所/监管机构最新公告为准。