Skip to content

金融技术工具 ​

🛠️ 量化分析 = 数据 + 代码 + 框架 —— 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数据特点
TushareA 股 / 基金 / 期货需积分
AKShareA 股 / 港美 / 宏观经济免费
BaostockA 股历史免费、稳定
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 Pro200-2000 元/年A 股 / 港美 / 期货 / 基金高
AKShare免费A 股 / 港美 / 宏观 / 行业中
Baostock免费A 股高
Wind2-10 万/年全市场极高
iFinD1-5 万/年全市场极高
聚宽 / 米筐 / 优矿1-5 万/年A 股高

📊 学习路径 ​

入门(1-3 月)
  - Python 基础
  - pandas / numpy
  - akshare / tushare
  ↓
进阶(3-6 月)
  - 因子计算
  - 回测框架
  - 财务分析
  ↓
实战(6-12 月)
  - 完整策略
  - 风控体系
  - 实盘对接
  ↓
专业(12+ 月)
  - 高频 / CTA
  - 多策略组合
  - 机器学习选股

📖 相关阅读 ​

💡 数据来源:AKShare 官方文档、Tushare 官方文档、Backtrader 官方文档、Wind 数据库。数据截至 2026-08。

来源 ​

💡 数据截至 2026-08;具体规则以交易所/监管机构最新公告为准。

本知识库内容仅供学习参考,不构成任何投资建议。
本站总访问量 ... 次 · 访客数 ... 人