3. HistoryPanel を使用して履歴データを操作および分析します

最初の 2 章「はじめに」と「財務データの取得と管理」を完了すると、すでに次のことができるようになります。

  • データ ソースをローカルで構成し、必要な履歴データをダウンロードします。

  • 価格や取引量などの基本的な市場データを取得するには、get_history_data() または get_history_panel() を使用します。

これに基づいて、この章では完全な小さな例を使用して、HistoryPanel の使用方法を示します。

  • 複数の金融商品や複数の指標の履歴データを一元管理。

  • リターンやボラティリティなどの単純な要素を計算します。

  • Kラインテクニカル指標をオーバーレイします。

  • ローソク足のパターンをいくつか特定します。

  • where to generate a bool mask with the same shape as the data, in preparation for subsequent research APIs that take mask= を使用します。

  • 列属性 (例: hp.close), comparison operators (returning a numpy boolean array that can be chained with where), and hp.loc (filters only along the time axis, equivalent to hp[:, :, key])。

より完全な API の説明については、HistoryPanel API リファレンス (「列属性のアクセス、比較、および loc” and on where」に関する専用セクションを含む) を参照してください。


3.1. 1. 准备数据:获取一个 HistoryPanel

CSI 300 Index (000300.SH) の過去 1 年間の日次データをすでにダウンロードしていると仮定します。 qt.get_kline() または qt.get_history_data() を介して HistoryPanel を直接取得できます。

import qteasy as qt

# 获取近一年日线 OHLCV,并直接返回 HistoryPanel
hp = qt.get_kline(
    shares='000300.SH',
    start='20230101',
    end='20231231',
    freq='D',
    as_panel=True,              # 关键:返回 HistoryPanel
)

print('HistoryPanel 结构:', hp.shape)
print('shares:', hp.shares)
print('htypes:', hp.htypes)

この時点で:

  • hp.shape(L, R, C) タプルであり、銘柄数 × 時間の長さ × データ型の数 に対応します。

  • hp.shares は通常、['000300.SH'] です。

  • デフォルトでは、hp.htypes には ['open', 'high', 'low', 'close', 'vol'] などが含まれます。


3.2. 2. 计算收益率与波动率因子

HistoryPanel には、価格シリーズのリターンとボラティリティを計算するためのインターフェースが組み込まれています。

# 2.1 计算简单收益率(simple return)
ret = hp.returns(
    price_htype='close',
    method='simple',    # 或 'log'
    periods=1,
    as_panel=False,     # 返回 DataFrame: index=时间, columns=shares
)
print('日收益率:\n', ret.tail())

# 2.2 在收益率基础上计算 20 日滚动波动率
vol = hp.volatility(
    window=20,
    price_htype='close',
    method='simple',
    annualize=True,     # 年化波动率
    as_panel=False,     # 同样返回 DataFrame
)
print('20 日年化波动率:\n', vol.tail())

典型的な使用法は次のとおりです。

  • ret または vol を因子値行列 (時間 × 株式) として扱います。

  • バックテスト エンジンに直接入力することも、銘柄選択やスコアリングなどに使用することもできます。


3.3. 3. 叠加 K 线技术指标

HistoryPanel に OHLC データが含まれている場合、hp.kline を介して一般的に使用される一連のテクニカル指標にアクセスできます。

# 基于 close 价格生成 20 日简单移动平均线
hp_ma = hp.kline.sma(window=20, price_htype='close')
print('新增 htypes:', hp_ma.htypes)

# 再叠加 MACD 指标
hp_ma_macd = hp_ma.kline.macd(price_htype='close')
print('叠加 MACD 后的 htypes:', hp_ma_macd.htypes)

# 将单只股票切成 DataFrame,方便在 pandas / sklearn 中继续处理
df_300 = hp_ma_macd.to_share_frame('000300.SH')
print(df_300.tail())

ここ:

  • hp.kline.sma(...) は、sma_20 などの列を htypes に追加します。

  • hp.kline.macd(...) は、macd_xxxmacd_signal_xxxmacd_hist_xxx の 3 つの列を追加します。

  • 最後に、to_share_frame(share) を使用して標準 2D DataFrame を取得します。これは、他のデータ ソースと組み合わせて直接分析できます。

3.1 inplace: 列をその場で展開します (コピーを減らします)

デフォルトでは、kline.*新しい HistoryPanel (元のオブジェクトを変更せずに) を返します。同じパネルに複数の列を連続して追加し、中間オブジェクトを減らしたい場合は、inplace=True を使用できます。

# 在原面板上原地追加两列,并返回原面板(支持链式)
hp2 = hp.kline.sma(window=20, inplace=True).kline.macd(inplace=True)
assert hp2 is hp
print('原地扩列后的 htypes:', hp.htypes)

ヒント: 新しい列名が既存の列名と競合する場合、サイレント上書きを避けるために、kline.* は英語の ValueError を生成します。

3.2 最初のエントリ ポイント:research_preset (一行の列チェーン + 直接プロット)

「データを入手したらすぐに見栄えの良いグラフを取得」したい場合は、research_preset を直接使用して、一般的に使用される列の公式プリセット セットを生成することをお勧めします (プリセットは明示的に追加のみを行い、plot() 内の計算を非表示にしません)。

# 生成 OHLCV + MACD + SMA20(预设名以 API 文档为准)
hp_preset = hp.research_preset('ohlcv_macd_ma', inplace=False)
print('preset htypes tail:', hp_preset.htypes[-8:])

# 多标的时可分页展示(不再静默只画前 5 只)
fig = hp_preset.plot(shares=hp_preset.shares, max_shares_per_figure=3, page=1)

入力パネルにプリセットに必要な入力列がない場合は、英語の ValueError が表示されます。メッセージには、不足している列のリストと、それらを埋める方法に関する提案が含まれています。


3.4. 4. 使用 assign 一次派生多列

実際の研究では、スプレッド、比率、スケーリング正規化値など、既存の列から複数の新しい要素を導き出す必要があることがよくあります。 HistoryPanel.assign() は、複数の列を一度に導出する DSL を提供します。

# 假设 hp 已含 'close' 和 'open' 列
hp2 = hp.assign(
    spread=lambda p: p['close'].values[:, :, 0] - p['open'].values[:, :, 0],
    up_ratio=lambda p: p['close'].values[:, :, 0] / np.maximum(p['open'].values[:, :, 0], 1e-6),
)
print('新列:', hp2.htypes[-2:])
  • assign のキーワード引数名​​は新しい列名 (htype) です。値は、現在の HistoryPanel を受け取る呼び出し可能関数、または (M,L) にブロードキャストできる配列/スカラーにすることができます。

  • 同じ呼び出し内で、後の列は前に追加したばかりの列に依存できます。次に例を示します。

hp3 = hp.assign(
    a=lambda p: p['close'].values[:, :, 0] + 1.0,
    b=lambda p: p['a'].values[:, :, 0] * 2.0,
)

デフォルトでは inplace=False で、元のオブジェクトを変更せずに新しいパネルを返します。元のパネル上の所定の位置で列を展開する場合は、次を使用できます。

hp.assign(inplace=True, factor=lambda p: p['close'].values[:, :, 0] / 100.0)

ヒント: hp['col'] = ... と同様、assign は既存の列名に「上書き」セマンティクスを使用します。空のパネルで assign を呼び出すと、英語の ValueError が発生します。


3.5. 5. 横截面 rank 与 zscore(cs/ts)

マルチアセットの研究では、次の 2 つのタイプの標準化ニーズが一般的です。

  • 横断的: 取引日を固定し、すべての株式のファクター値を標準化またはランク付けします。

  • 時系列 (ローリング): ストックを固定し、ローリング ウィンドウを使用して独自の履歴シリーズを標準化します。

HistoryPanel.rank()HistoryPanel.zscore() は、これら 2 つのタイプの最も基本的な変換を提供します (変換のみ、回帰推論なし)。

# 5.1 截面排名:逐日对 share 维做排名
hp_rank = hp.rank(by='close')                  # 追加一列 'rank_close'

# 5.2 截面 zscore:逐日横截面标准化(method='cs')
hp_cs = hp.zscore(by='close', method='cs')     # 追加一列 'cs_z_close'

# 5.3 时序 zscore:逐股滚动标准化(method='ts',需要 window)
hp_ts = hp.zscore(by='close', method='ts', window=20)   # 追加一列 'ts_z_close_20'

注: zscore(method='cs')zscore(method='ts') は完全に異なるセマンティクスを持ちます。 「横断的な標準化」と「時系列の標準化」を間違えないように、必ずmethodを明示的に指定してください(tsの場合はwindowも指定してください)。

5.5 アライメントとリサンプリング (align_to / resample): サイレントな行の位置ずれを回避する

したがって、2 つの HistoryPanel があり、要素ごとの操作 (hp_factor / hp_price や 2 つのパネルの減算など) を実行する場合は、特別な注意を払う必要があります。

  • HistoryPanel 演算子内の 2 つのパネルを自動的に整列させることはありません

  • shares / hdates に一貫性がない場合、.values で直接 NumPy 操作を実行すると、「計算しているように見えても、実際には行ごとに位置がずれている」結果が簡単に生成される可能性があります。

したがって、最初に位置合わせしてから計算という、固定されたワークフローに従うことをお勧めします。

# hp_a 与 hp_b 的 shares/hdates 不一定一致
a1, b1 = hp_a.align_to(hp_b, join='inner')   # 交集对齐:只保留共同 shares 与共同日期
ratio = a1.values / b1.values                # 此时逐元素运算不会错行
print('aligned shape:', a1.shape, b1.shape)

=日次データを週次/月次などの低頻度データに変換する必要がある場合は、resample() を使用し、明示的に各列の集計ルールを指定できます (意味が不明瞭になるのを避けるため)。

# 典型 OHLCV 周线:open=first, high=max, low=min, close=last, vol=sum
hp_w = hp.resample('W', agg={
    'open': 'first',
    'high': 'max',
    'low': 'min',
    'close': 'last',
    'vol': 'sum',
})
print('weekly dates:', hp_w.hdates[:3], '...')

注: resample() では、すべての htypes をカバーするには agg が必要です。 OHLCV ではないカスタム要素列の場合は、集計方法を自分で決定し (例: 'last' / 'mean')、それを agg に含める必要があります。

5.6 (M, L) マスクを使用してプロットを強調表示する (イベント日 / シグナル日)

ファクター調査では、多くの場合、「各銘柄が条件を満たす日付」(イベント日、シグナル日、取引可能なユニバースなど)を示す 2D ブール行列 mask_ml を取得します。

HistoryPanel.plot()highlight={'condition': mask_ml} は、ポイントを強調表示するためにチャートに直接マッピングすることをサポートしています。

  • mask_ml.shape == (M_plot, L) の場合、M_plotplot(shares=...) によって現在選択されている銘柄の数であり、プロットされた株式順序に対応します。

  • mask_ml.shape == (M_all, L)M_all == len(hp.shares) の場合、共有名 によって現在のプロット サブセットを抽出します (サイレントな行の位置ずれを避けるため)。

  • layout='overlay' の場合、ハイライトはデフォルトで プライマリのみ として表示されます (既存の Plotly ハイライト セマンティクスと一致します)。

import numpy as np

M, L, _ = hp.shape
mask_ml = np.zeros((M, L), dtype=bool)
mask_ml[:, -1] = True                      # 举例:每只股票的最后一天高亮

fig = hp.plot(
    shares=hp.shares,
    layout='stack',
    highlight={'condition': mask_ml},
)

5.4 Newey-West / Fama-MacBeth (背景: このセクションでは実装されていません)

経験的計量経済学では、Newey-West (HAC) の堅牢な標準誤差Fama-MacBeth の 2 段階回帰が見られることがあります。これらは主に 回帰推論 (標準誤差補正、リスク プレミアムの有意性検定) に使用され、HistoryPanel.zscore() のような「基本的な変換」ではありません。出版グレードの実証作業が必要な場合は、HistoryPanelDataFrame にエクスポートし、statsmodels などのツールを使用して推論ワークフローを完了することをお勧めします。


3.6. 6. 使用 apply_ta 统一调用技术指标

qteasy.tafuncs または ta-lib にすでに慣れている場合は、統合ラッパーとして HistoryPanel.apply_ta() を使用できます。

# 在所有股票上应用 'sma' 指标,对 close 做 10 日均线
hp_sma10 = hp.apply_ta(
    func_name='sma',
    htype='close',
    timeperiod=10,
    as_panel=True,      # 返回新的 HistoryPanel,追加一列 'sma'
)
print('htypes with sma:', hp_sma10.htypes)

これにより、ループ内でtafuncs.sma を手動で呼び出すことがなくなります。 HistoryPanel は、選択されたすべての銘柄にわたって計算を自動的にブロードキャストします。


3.7. 7. 识别蜡烛形态

OHLC データの場合、HistoryPanel.candle_pattern() を介して ta-lib のローソク足パターン認識関数をラップすることもできます。例:

# 识别锤头线形态(CDLHAMMER),返回时间 × 股票的整数信号矩阵
hammer = hp.candle_pattern(
    name='cdlhammer',
    as_panel=False,          # 返回 DataFrame
)
print('锤头线信号(非 0 代表出现形态):\n', hammer[hammer != 0].dropna(how='all'))

通常、信号の意味は次のとおりです。

  • 0: パターンが検出されません。

  • 正/負の値: 異なる方向または異なる強度で信号をパターン化します (特定の ta-lib 関数の定義に応じて)。


3.8. 8. 生成研究用 bool 掩码(where

パネルの軸順序values is (number of assets M, time length L, number of indicator columns N), consistent with hp.shape. hp.where(condition) returns a same-shape numpy.ndarray, dtype=bool, and does not modify hp. ⟦C ODE12⟧, normalize, and portfolio already support mask=hp.where(...) (or a bool array with the same broadcasting rules as where)。研究指向のセマンティクスとエッジ ケース (パス ブレーク、無効な基準日、ポートフォリオとベンチマークの関係など) については、API docstring を参照してください。

値の完全な表と比較 (hp.values > threshold に相当):

import numpy as np

mask = hp.where(hp.values > 0)   # 或先写 cond = hp.values > 0 再 hp.where(cond)
assert mask.shape == hp.shape
print('True 格点数量:', int(mask.sum()))

時間次元に沿ったラベル付け (たとえば、特定の列のインデックスが「イベント日」の場合、すべての htype にわたってそれを複製します。以下は例示です。cond_ml has shape (M, L) であることを確認してください):

M, L, N = hp.shape
cond_ml = np.zeros((M, L), dtype=bool)
cond_ml[:, -1] = True   # 示例:最后一个交易日标记为 True
mask_event = hp.where(cond_ml)
assert mask_event[:, -1, :].all() and not mask_event[:, 0, :].any()

終値列に基づいて条件を構築します (callable receives the current HistoryPanel):

# 假设存在 'close' 列;多列面板可用 p.values[:, :, idx] 或子面板
mask_close = hp.where(lambda p: p['close'].values[:, :, 0] > 0)

複合条件と欠損値:

mask_band = hp.where(lambda p: (p.values > -1e9) & (p.values < 1e9))
mask_nan = hp.where(np.isnan(hp.values))   # 标记 NaN 所在格,供排除缺失

注意: 正確な形状を持つ 2D 条件⟦コード0⟧⟦コード1⟧⟦コード2⟧⟦コード3⟧⟦コード4⟧⟦コード5⟧⟦コード6⟧⟦コード7⟧⟦コード8⟧⟦コード9⟧⟦コード10⟧⟦コード11⟧⟦コード12⟧ HistoryPanel API リファレンス のセクション。

8.1 累積リターンと正規化 (cum_return / normalize)

新しいを返します⟦コード0⟧⟦コード1⟧⟦コード2⟧⟦コード3⟧⟦コード4⟧⟦コード5⟧⟦コード6 ⟧⟦コード7⟧⟦コード8⟧⟦コード9⟧⟦コード10⟧⟦コード11⟧⟦コード12⟧)。マスクと併用可能:

m = hp.where(hp.close > 0)           # 或与 hp.values 比较得到 (M,L,N)
cr = hp.cum_return(mask=m, method='simple')
nm = hp.normalize(base_index=0, mask=m)

8.2 ポートフォリオの集計 (portfolio)

研究指向: 資産ディメンションに沿って指定された列の均等加重平均または加重平均を取得し、新しいを返します。 HistoryPanel (hdates unchanged). mask= follows the same broadcasting rules as where. When there are no ``groups⟦コード9⟧⟦コード10⟧⟦コード11⟧⟦コード12⟧⟦コード13⟧⟦コード14⟧⟦コード15⟧⟦コード16⟧)。アカウントのバックテストではありません。取引コストはかかりません。詳細については、API ドキュメント文字列を参照してください。

ew = hp.portfolio(mode='equal', benchmark_output='none')
m = hp.where(hp.close > 0)
ew_m = hp.portfolio(mode='equal', mask=m, benchmark_output='none')
# 含基准指数代码 'IDX' 时:
# tagged = hp.portfolio(mode='equal', benchmark='IDX', benchmark_output='tag_along', new_share_name='EW')

8.3 列の属性、比較、および loc (pandas との違いについての簡単なメモ)

  • 列属性 (読み取り専用): 列名が有効な Python 識別子の場合、hp.close, equivalent to hp['close']; adjusted-price column names containing | and the like must use brackets. For assignment, consistently use hp['col'] = ... を使用できます。

  • 比較: のような表現⟦コード0⟧⟦コード1⟧⟦コード2⟧⟦コード3⟧⟦コード4⟧⟦コード5⟧⟦コード6⟧⟦コード7⟧⟦コード8⟧⟦コード9⟧⟦コード10⟧⟦コード11⟧⟦コード12⟧一致する必要があります。 2 つの列を比較する場合、通常は 2 つの 単一列 サブパネルです。

  • **⟦コード0⟧⟦コード1⟧⟦コード2⟧⟦コード3⟧⟦コード4⟧⟦コード5⟧⟦コード6⟧⟦コード7⟧⟦コード8⟧⟦コード9⟧⟦コード10⟧⟦コード11⟧⟦コード12⟧⟦コード13⟧⟦コード14⟧

詳細と特殊なケースについては、HistoryPanel API リファレンス (where, cum_return, normalize, portfolio を含む) を参照してください。

# 示意(在已含 open/close 列的 hp 上)
# m = hp.where(hp.close > hp.open)   # 比较 → bool ndarray → where 广播到 (M,L,N)
# tail = hp.loc[-5:]                 # 仅时间轴,等价 hp[:, :, -5:]

3.9. 9. 从 HistoryPanel 研究到 Strategy / Operator:迁移路径

HistoryPanelcum_returnportfolioplot などは 研究指向 ツールです。要因に注目したり、ポートフォリオの大まかな曲線を表示したりするのに便利ですが、決済サイクル、手数料、スリッページ、シグナル タイプの解析などの正式なバックテストと一致するアカウント セマンティクスは 含まれません (PT/PS/VS)。結論をライブ取引や本格的な評価に使用する場合は、同じ経済的意味を持つルールをストラテジーの realize() に書き込み、それらを Operator + Backtester に渡す必要があります。

以下では、同じアイデアである 20 期間の単純な勢い を使用して 2 つのステージを接続します (データ ソースがローカルに構成され、対応するフィールドがダウンロードされている必要があります。ストック コードは説明のみを目的としています)。

9.1 研究段階: マルチアセット HistoryPanel の係数を計算し、断面をざっと確認します

import numpy as np
import qteasy as qt

# 多标的日线收盘价(htype 以你本地数据源为准,可为 close 或复权列如 close|b)
hp = qt.get_history_data(
    htypes='close',
    shares=['000001.SZ', '000002.SZ', '600000.SH'],  # 示例股票池
    start='20200101',
    end='20231231',
    freq='d',
)

# 20 期简单收益 r_t = P_t / P_{t-20} - 1,直接得到带标签的子面板
hp_mom = hp.returns(price_htype='close', periods=20, method='simple', as_panel=True)

# 截面排名:逐日看多标的谁强谁弱(研究向)
hp_rank = hp_mom.rank(by='ret_close')

# 可选:等权「组合」在收益列上的逐日平均,仅用于目视,非账户回测
hp_ew = hp_mom.portfolio(htypes='ret_close', mode='equal', benchmark_output='none')

hp_mom.plot(shares=hp_mom.shares, layout='stack')   # 结合前几节 mask 高亮更佳

これで、3D パネル上での因子列の生成、断面変換、および大まかな集計が完了しました。結果が良好であれば、9.2 に進み、要素定義を戦略に移動します。

9.2 正式なバックテスト段階: FactorSorter + Operator

銘柄選択戦略では通常、FactorSorter: realize()商品ごとに 1 つのスカラー係数 (長さ = 株の数) を返し、フレームワークは max_sel_countsort_ascending などに基づいて重み付けをソートして割り当てます。 以下のモメンタムは 9.1 の returns(..., periods=20) と同じ経済的意味を持ちますが、データは戦略ウィンドウ (バックテストのステップと調整され、use_latest_data_cycle などによって制約されます)。

import numpy as np
import qteasy as qt
from qteasy import StgData


class Mom20Factor(qt.FactorSorter):
    """20 期收盘动量:close[-1]/close[0]-1,与 HP 上 returns(periods=20) 语义对齐。"""

    def __init__(self) -> None:
        super().__init__(
            name='Mom20',
            description='20-bar simple momentum on daily close',
            data_types=[StgData('close', freq='d', asset_type='E')],
            window_length=21,
            max_sel_count=3,
            sort_ascending=False,
            condition='any',
            use_latest_data_cycle=True,
        )

    def realize(self):
        close_w = self.get_data('close_E_d')   # 形状约为 (window_length, 股票数)
        out = close_w[-1] / close_w[0] - 1.0
        out = np.where(np.isfinite(out), out, np.nan)
        return out


# 以下为骨架:具体 run 参数(股票池、起止日、费率、signal_type 等)见「回测」与 Operator 文档
op = qt.Operator()
op.add_strategy(Mom20Factor(), run_freq='d', run_timing='close')
# res = qt.run(op, mode=1, ...)  # 按项目文档填写 shares、起止日期与回测配置

注記

  • デフォルトでは、Operator はグループ内で PT クラスのターゲット位置信号の使用を許可します。 FactorSorter と PT をどのように組み合わせるかは、プロジェクトの戦略ドキュメントに従う必要があります。

  • 完全なサンプルを使用して HP で計算されたランク/Z スコアは、「各ステップで履歴ウィンドウのみが表示される」バックテストの要素とは数値的にわずかに異なる場合があります。これは予想されることです。先読みバイアスを防ぐために、戦略内で get_data を使用して再チェックする必要があります。

完全な実行可能なスクリプトについては、プロジェクトのルート ディレクトリにある examples/historypanel_research_to_strategy.py を参照してください。


3.10. 10. 多源数据拼成 HistoryPanel(价格 + 基本面示例)

HistoryPanel は任意の htypes 列を保持できます。 複数のテーブル/複数の DataTypes に対する一般的なアプローチは次のとおりです。(1) 1 回の get_history_data 呼び出しで複数の列をフェッチします。 (2) または 2 つのパネルを個別に取得して、align_to を実行します。

10.1 複数の列を一度に取得する (頻度と資産タイプは一貫している必要があります)

ローカルに毎日の close および pb (予約価格) フィールドがすでにある場合は、次の操作を直接行うことができます。

import numpy as np
import qteasy as qt

hp = qt.get_history_data(
    htypes='close, pb',
    shares=['000001.SZ', '000002.SZ'],
    start='20200101',
    end='20231231',
    freq='d',
)

# 估值倒数近似账面市值比(仅作演示,非投资建议)
hp2 = hp.assign(bp=lambda p: 1.0 / np.maximum(p['pb'].values[:, :, 0], 1e-8))

# 横截面 zscore:逐日可比
hp_z = hp2.zscore(by='bp', method='cs')

列が欠落している場合、またはテーブルがダウンロードされていない場合、get_history_data はエラーを発生させます。まず、データ ソース チュートリアルを通じてテーブル データを完成させてください。

10.2 最初に 2 つのパネルを位置合わせしてから派生します (異なるソース/異なるプル)

align_to requires that the htypes names and order match exactly on both sides. If you only fetched the close and pb columns separately, you need to first expand them into a homogeneous set of columns (use NaN as placeholders on the missing side), then after alignment use assign を使用して、有効な値を同じ列名のセットに書き戻します。

import numpy as np
import qteasy as qt

hp_px = qt.get_history_data(htypes='close', shares=pool, start='20200101', end='20231231', freq='d')
hp_pb = qt.get_history_data(htypes='pb', shares=pool, start='20200101', end='20231231', freq='d')

c = hp_px['close'].values[:, :, 0]
p = hp_pb['pb'].values[:, :, 0]
nan_c = np.full_like(c, np.nan)
nan_p = np.full_like(p, np.nan)

hp_a = qt.HistoryPanel(
    np.stack([c, nan_p], axis=2),
    levels=hp_px.shares,
    rows=hp_px.hdates,
    columns=['close', 'pb'],
)
hp_b = qt.HistoryPanel(
    np.stack([nan_c, p], axis=2),
    levels=hp_pb.shares,
    rows=hp_pb.hdates,
    columns=['close', 'pb'],
)

a, b = hp_a.align_to(hp_b, join='inner')
hp_joined = a.assign(
    close=lambda x: a['close'].values[:, :, 0],
    pb=lambda x: b['pb'].values[:, :, 0],
)

同じことが他の分野 (業界、時価総額など) にも当てはまります。 get_history_data(htypes='close, pb', ...) のように 1 回の呼び出しでそれらをフェッチできる場合は、1 回の手動均質化ステップを避けるために §10.1 を推奨します。 NumPy が暗黙的に行の位置をずらすことを避けるために、核となる原則は依然として 最初に位置合わせしてから計算 です。

実行可能な合成データのデモについては、プロジェクトのルート ディレクトリにある examples/historypanel_multisource_research.py を参照してください。


3.11. 11. 导出到 pandas / statsmodels(宽表、长表与截面回归)

HistoryPanel には、Newey-West や Fama-MacBeth などの組み込みの推論ワークフローがありません。出版グレードの回帰が必要な場合は、2D テーブルにエクスポートしてから、statsmodels などのライブラリを使用する必要があります。

11.1 資産ごとに複数の DataFrame に分割 (ワイドテーブル)

by_share = hp.to_df_dict(by='share')
df_000001 = by_share['000001.SZ']   # index 为时间,columns 为 htypes

11.2 成長表を手動で積み重ねる (日々の横断的なグループ化を容易にするため)

import pandas as pd

records = []
M, L, N = hp.shape
ci = hp.htypes.index('close')
fi = hp.htypes.index('factor')   # 假设已存在名为 factor 的列
for mi, sh in enumerate(hp.shares):
    for li, dt in enumerate(hp.hdates):
        records.append({
            'date': dt,
            'share': sh,
            'close': hp.values[mi, li, ci],
            'factor': hp.values[mi, li, fi],
        })
df_long = pd.DataFrame(records)

11.3 1 日の横断的な OLS の例 (統計モデルのインストールが必要)

# pip install statsmodels
import statsmodels.api as sm

sub = df_long[df_long['date'] == df_long['date'].iloc[-100]].dropna()
y = sub['close'] / sub['close'].mean() - 1.0   # 示例因变量,实际常用前瞻收益
X = sm.add_constant(sub['factor'])
model = sm.OLS(y, X, missing='drop').fit()
print(model.summary())

上記の従属変数はデモンストレーションのみを目的としています。実際には、要因をフォワード リターンと調整し、一時停止や生存者バイアスなどを処理する必要があります。これらすべては、HistoryPanel の中核的な責任としてではなく、計量経済学レイヤーで行う必要があります。

合成データの例については、プロジェクトのルート ディレクトリにある examples/historypanel_statsmodels_export.py を参照してください。


3.12. 12. 小结与下一步

この章の例を通して、次のことがわかります。

  • HistoryPanel は、複数の金融商品/複数の指標にわたる共同研究に適した、統合された 3D 履歴データ コンテナを提供します。

  • その上で、統計手法 (describe/mean/std/min/max)、ローリング ウィンドウ (rolling)、リターン/ボラティリティ (returns/volatility)、横断的なランキングと標準化 (rank/zscore)累積リターンと正規化を直接呼び出すことができます。 (cum_return/normalize)ポートフォリオ集計 (portfolio)、ローソク足 (K ライン) インジケーター (kline.*)、テクニカル指標ブリッジング (apply_ta)、ローソク足パターン認識 (candle_pattern)、リサーチマスク(where)、および 列属性/比較/loc など。

  • どの段階でも、簡単に DataFrame に切り替えて、pandas / sklearn / statsmodels などと連携できます。

  • 正式なバックテストの場合は、Strategy.realize + Operator を使用します。研究指向の HP とバックテスト エンジンの間の境界と移行パスについては、§9 を参照してください。

推奨される次のステップ:

  • ノートブックで、独自の株式ユニバースに基づいて HistoryPanel を構築し、複数の要素 (移動平均、ボラティリティ、バリュエーションなど) を積み重ねて、価格に合わせてチャートをプロットしてみます。

  • HistoryPanel API リファレンス を読んだことに基づいて、研究テーマのワークフローを設計します: 「データ → 要因 (HP) → ルールの固定化 (戦略) → バックテスト (Operator)」。

  • 別の「因子評価」API ラッパーを追加するかどうかを検討している場合は、設計ノート HistoryPanel およびオプションの FactorResearch レイヤー を読むことができます。