3. HistoryPanel
This chapter introduces HistoryPanel: Building upon an understanding of DataType, it demonstrates how to consolidate historical data from multiple targets, metrics, and the same timeline into a single “panel” and reuse it across strategy research, backtesting preparation, and visualization. Reading this chapter does not require prior reading of Local Data Source, but if you have not yet populated your local data source with data, please complete the download and configuration before using get_history_data to retrieve data.
In the previous chapter, we saw that qteasy uses DataType to abstract the “raw columns in the data table” into information that can be directly consumed by the strategy and backtesting. When this information needs to be aligned to the same timeline with multiple targets and various data types (such as OHLC, volume, MACD, etc.), manually concatenating multiple DataFrames is not only prone to errors, but also hinders the reuse of the same data structure between the strategy code and the visualization code.
HistoryPanel is a container designed for this scenario: internally, it organizes data into a three-dimensional structure of shares × index × htypes, allowing you to slice and filter shares or metrics using a unified interface, and reuse the same object in subsequent backtesting, strategy logic, or plotting. For most users, you don’t need to worry about how the panel interacts with the local data source internally; after obtaining the HistoryPanel through familiar workflows such as get_history_data, you can use it as a “time-aligned, multi-shared, multi-metric data set”.
This chapter explains the core concepts and common uses of HistoryPanel; the next chapter, HistoryPanel Visualization, builds upon this to introduce how to use hp.plot() to directly plot the same panel as a static or interactive graph. The lower-level data retrieval API functionalities are only briefly listed in API Reference to avoid confusion with common paths.
3.1. Core concepts: 3D structure and shape
The HistoryPanel corresponds to a three-dimensional numpy.ndarray in memory, with the three axes as follows:
axis |
Meaning |
Common properties |
|---|---|---|
0th dimension |
Target (stock code, etc.) |
|
1st dimension |
Time (historical date or moment) |
|
2nd dimension |
Data types (such as |
|
shape returns (number of targets, time duration, number of data types), in the same order as above. It can be understood as: many two-dimensional tables of “time × metric” are stacked on top of each other in the target direction; within the same panel, the targets and metrics are aligned in time.
Compared to a single-index wide table DataFrame (rows are time, columns are indices), HistoryPanel explicitly places multi-index in the 0th dimension, which facilitates batch operations and index-based slicing, without having to maintain multiple MultiIndex columns.
(Illustrative diagram: The “3D block” can be understood as L layer index × R row time × C column index; an illustration can be added in a later version if needed.)
3.2. How to obtain HistoryPanel
The recommended approach is to use **qt.get_history_data(..., as_data_frame=False): assuming the required data is already available in the local data source, you can obtain the aligned HistoryPanel by specifying htype_names (consistent with the DataType naming, see the previous chapter) along with shares, the time range, or rows.
By default, get_history_data sets as_data_frame to True, returning a dict[str, DataFrame] grouped by index, suitable for quickly viewing single-index data; when a 3D panel is required, be sure to pass as_data_frame=False. For complete parameter, frequency, and weighting information, please see Historical Data API.
The example below does not rely on the network and uses a small array to construct the panel, making it easy to understand the shape and labels; in actual work, get_history_data can be used to populate it from a local data source instead.
import numpy as np
import pandas as pd
from qteasy import HistoryPanel
# 2 只标的、4 个交易日、3 种数据类型 → shape (2, 4, 3)
values = np.array(
[
[[1.0, 1.1, 100], [1.2, 1.3, 110], [1.15, 1.2, 105], [1.25, 1.28, 120]],
[[10.0, 10.5, 200], [10.2, 10.8, 210], [10.1, 10.4, 205], [10.3, 10.9, 215]],
],
dtype=float,
)
hp = HistoryPanel(
values=values,
levels=['000001.SZ', '000002.SZ'],
rows=pd.date_range('2025-01-02', periods=4, freq='B'),
columns=['open', 'high', 'vol'],
)
print(hp.shape) # (2, 4, 3)
print(hp.shares) # 标的列表
print(hp.htypes) # 数据类型列表
If local market data is already available, it can be changed to:
import qteasy as qt
hp = qt.get_history_data(
htype_names='open, high, low, close, vol',
shares='000001.SZ',
rows=60,
as_data_frame=False,
)
print(hp.shape, hp.shares, hp.htypes)
3.3. Basic operations: time range, target and indicator subset
The following methods narrow down your current focus without changing the data retrieval semantics; the return value is still HistoryPanel (except for empty panels).
By date range:
segment(start_date, end_date), all time rows within the closed range; the dates can be consistent with the granularity inhdates(daily frequency, intraday, etc.).By row number range:
isegment(start_index, end_index), similar to Python slicing, is suitable for extracting segments by position.**Recently recent lines:
head(n)/tail(n).Filter by target and/or indicator name:
slice(shares='A, B', htypes='close, vol'), either a string or a list is acceptable.
When performing pandas analysis on single-index or multi-index data, you can use to_share_frame(share) to obtain a DataFrame for that index (with time as the index and htypes as the columns). For more information on exporting multi-index data, please refer to the API documentation for to_df_dict and other related documentation.
In the Operator and backtesting process, historical data is often injected in groups during the strategy execution scheduling phase; specific parameters and schedule configurations can be found in the relevant chapter of “Creating and Operating Trading Strategies”. Here, it’s sufficient to establish the following: Strategies and visualizations can both revolve around the same HistoryPanel (or its slices), thereby reducing the repetitive organization of “one set of data in multiple formats”.
3.4. Metrics and column extensions (kline, etc.)
Building upon the existing price class htypes, you can access common derived columns such as moving averages, MACD, and Bollinger Bands via the hp.kline accessor. These methods typically return a new HistoryPanel: appending indicator columns to the third dimension, without modifying the original object, and keeping shares and hdates consistent with the original panel. Adjusted column names (such as close|b) will be aligned with the parsing logic of kline, returns, etc., in newer versions; if both raw and adjusted column names exist in the panel, it is recommended to read the behavior description in the HistoryPanel API.
More complete examples of factor-based methods (returns, volatility, apply_ta, etc.) can be found in the tutorial Using HistoryPanel to manipulate and analyze historical data.
3.5. Summary and Next Steps
HistoryPanel provides a unified container of (target × time × data type), suitable for research and backtesting preparation with multiple targets, multiple metrics, and time alignment.
The
get_history_data(..., as_data_frame=False)function is commonly used to retrieve the data frame; by default, you can first read the previous chapter on DataType naming andget_dtype_map().Slices and subsets: segment / isegment / head / tail / slice; Exporting a single frame: to_share_frame.
Next Chapter HistoryPanel Visualization: Using
hp.plot()to create static or interactive plots.If local data is not ready, please read Local Data Source and Data Fetching and Channels first.