σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft Academy学习路线
Ctrl K
AO
+1.2k 位学习者
登录加入 ↗
学习路线
AO
+1.2k 位学习者
登录
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Python 学习路线›模块 2 · 用于市场数据的 NumPy 与 pandas›主题 2.13·~40分钟中级

重采样

路线进度模块 2/11 · 主题 13/20
2.13 重采样
—实验得分— / 100总 XP—连续天数—

改变频率

数据很少恰好是你需要的频率。逐笔数据以毫秒到达,模型要日线,报告要月度。重采样会把时间序列重新划分到新的周期中。由细到粗(日到月)是降采样:每个新周期包含多个旧观测,所以必须说明如何合并;由粗到细(周到日)是升采样:出现了没有数据的新周期,所以必须说明填入什么。

import pandas as pd

daily = pd.Series(
    [100.0, 101, 103, 102, 104, 105, 103, 106],
    index=pd.bdate_range("2026-02-25", periods=8),    # Wed 25 Feb ... Fri 6 Mar
    name="close",
)

print(daily.resample("ME").last())     # the last price of each month ("ME" = month end)
# 2026-02-28    103.0
# 2026-03-31    106.0
# Freq: ME, Name: close, dtype: float64

print(daily.resample("W-FRI").last())  # the last price of each week, weeks ending on Friday
# 2026-02-27    103.0
# 2026-03-06    106.0
# Freq: W-FRI, Name: close, dtype: float64

选择聚合方式

单独的 series.resample("ME") 什么也不做,它只是描述周期。随后的聚合才决定取值,并且必须符合数据的含义。价格是快照,因此一个月用它的 last(或 first)值表示;成交量是成交数量,所以一个月取 sum;区间用 max 和 min。标签遵循规则:"ME" 用月份的最后一个自然日标记(即使是周六),"W-FRI" 用那一周的周五标记。

volume = pd.Series([10, 20, 30, 40, 50, 60, 70, 80], index=daily.index)

print(volume.resample("ME").sum().to_dict())
# {Timestamp('2026-02-28 00:00:00'): 60, Timestamp('2026-03-31 00:00:00'): 300}

# Several summaries at once
print(daily.resample("ME").agg(["first", "last", "max"]))
#             first   last    max
# 2026-02-28  100.0  103.0  103.0
# 2026-03-31  102.0  106.0  106.0

由逐笔数据生成K线与升采样

图表和模型使用 OHLC K线:每个周期的开盘(第一个价格)、最高、最低和收盘(最后一个价格)。resample("D").ohlc() 一次调用就能由日内价格生成它们。没有任何成交的自然日(如周末)仍会以 NaN 行出现,所以只想保留有交易的日子时,最后加上 dropna()。升采样则相反:resample("D").ffill() 在无数据的日子重复最近已知的值,这正是每周报价的价格的真实含义。价格永远不要用 bfill:它把未来的值向前复制,把明天的信息泄露到今天。

times = ["2026-03-05 09:30", "2026-03-05 11:00", "2026-03-05 15:59",
         "2026-03-09 09:30", "2026-03-09 12:00", "2026-03-09 15:59"]
ticks = pd.Series([100.0, 101.5, 99.8, 100.7, 102.0, 101.0], index=pd.to_datetime(times))

bars = ticks.resample("D").ohlc()
print(bars)
#              open   high    low  close
# 2026-03-05  100.0  101.5   99.8   99.8
# 2026-03-06    NaN    NaN    NaN    NaN
# 2026-03-07    NaN    NaN    NaN    NaN
# 2026-03-08    NaN    NaN    NaN    NaN
# 2026-03-09  100.7  102.0  100.7  101.0

print(bars.dropna().index.strftime("%d %b").tolist())   # ['05 Mar', '09 Mar']   only the days that traded
# Upsampling: observations on the 2nd, 6th and 10th, spread over every day with ffill
weekly = pd.Series([100.0, 103.0, 101.0], index=pd.to_datetime(["2026-03-02", "2026-03-06", "2026-03-10"]))

print(weekly.resample("D").ffill().tolist())
# [100.0, 100.0, 100.0, 100.0, 103.0, 103.0, 103.0, 103.0, 101.0]

print(int(weekly.resample("D").mean().isna().sum()))   # 6   without a fill rule the new days are empty
重采样可能泄露未来信息月度K线要到月底才能知道。如果把月末收盘价挂在该月第一天,策略就像预知了未来。像 "ME" 那样把标签放在周期末尾,升采样用 ffill(绝不用 bfill),并且把月度信号向前平移后再用于日度数据。
  • series.resample(规则) 描述周期("D"、"W-FRI"、"ME"、"h");其后的聚合计算取值。
  • 价格用 last 或 ohlc(),成交量用 sum;空周期显示为 NaN,用 dropna() 去掉。
  • 升采样需要填充规则:ffill() 重复最近已知的值;价格绝不用 bfill(),它会泄露未来。

下一节:滚动窗口,在最近若干期的滑动窗口上计算移动平均等统计量。

实验:评分内容

  • 用 month_end_close 取每个月的最后一个价格25 分
  • 用 weekly_volume 汇总每周的成交量25 分
  • 用 daily_ohlc 由日内价格生成日K线25 分
  • 用 fill_to_daily 把不规则的观测铺展到每一天25 分
资源管理器 · lab-46-1
▾ lab-46-1
…
bash · 浏览器内
learner@quantcraft:~/lab-46-1$
Python 尚未加载PythonLn 1, Col 1Spaces: 4UTF-8

要重置此主题吗?

lab-46-1 中的所有内容将恢复为初始文件,终端也会被清空。你当前的解答将丢失,且无法撤销。

将被重置
  • main.py → 初始代码
  • 终端历史与测试输出
  • 未提交的更改
将被保留
  • 实验最高得分
  • 你的 XP 与连续天数
  • 讲解进度与笔记

登录后即可运行你的代码。

所有讲解均可免费阅读。创建账户或登录后,即可运行代码、运行测试并提交此实验。

  • 浏览器内 IDE 与 bash 终端,无需安装
  • 即时评分、XP 以及你在学习路线中的位置
创建账户登录
或
使用 GitHub 继续