DataFrame
Published Last updated
Key Takeaway
A DataFrame is pandas' core two-dimensional data structure — a labelled table of rows and columns used to store, process, and analyse OHLCV price series throughout a trading bot's pipeline.
Learn These First
What Is DataFrame?
A DataFrame is pandas' core two-dimensional data structure — a labelled table of rows and columns used to store, process, and analyse OHLCV price series throughout a trading bot's pipeline.
How DataFrame Works
Frequently Asked Questions
What is a DataFrame and why is it used in trading bots?
A DataFrame is a two-dimensional, labelled data table from the pandas library — essentially a programmatic spreadsheet where each column has a name and each row has an index. In trading bots, DataFrames store OHLCV price series with each row representing one candle period and each column holding a specific value — open price, close price, RSI, or SuperTrend direction. The labelled structure means code reads `df['close']` instead of `data[4]`, making bot code self-documenting and significantly easier to debug and verify against the strategy specification it is meant to implement.
How does a DataFrame change as it moves through the trading bot pipeline?
A DataFrame evolves as it passes through each module. In data_fetcher, it starts as a five-column OHLCV table with timestamp, open, high, low, close, and volume. In the indicators module, new columns are appended — RSI_14, SuperTrend direction, and VWAP — expanding the table horizontally while keeping all rows aligned. In signal_logic, additional columns such as entry_signal and exit_signal are written based on row-level conditions. In backtesting, the same DataFrame is iterated row-by-row with the trade results collected into a separate trades DataFrame used for performance metric computation.
What is the difference between a DataFrame row and a DataFrame column in trading bot code?
In a trading bot DataFrame, columns represent data fields — each column holds one type of value across all candle periods, such as every closing price or every RSI reading. Rows represent individual candle periods — each row holds all data fields for one specific point in time. Accessing a column returns a complete time series: `df['close']` retrieves every closing price in the dataset. Accessing a row returns a complete snapshot: `df.iloc[i]` retrieves every data field — price, volume, and all indicators — for the single candle at position i in the chronological sequence.
Common Misconceptions About DataFrame
A DataFrame is just a list of lists with extra syntax — it does not add meaningful capability.
A DataFrame's labelled column structure provides substantially more than naming convenience. Column labels enable self-documenting code — `df['close']` is unambiguously clear while `data[4]` requires context to interpret. Boolean filtering — `df[df['RSI_14'] < 30]` — returns all rows where RSI is below 30 with no iteration required. Vectorised operations apply mathematical functions to entire columns simultaneously in a single line. DataFrame alignment ensures that appended indicator columns stay synchronised with their corresponding price rows. These capabilities collectively reduce hundreds of lines of manual data management code to a handful of concise, readable operations.
DataFrames store data permanently — modifying a DataFrame changes the original data.
In pandas, most operations return a new DataFrame rather than modifying the existing one in place, unless the `inplace=True` parameter is explicitly specified. This behaviour is important for trading bots: when the indicators module appends columns, best practice is to assign the result to the same variable name, confirming the modification explicitly. In J21's bot architecture, the OHLCV DataFrame is treated as append-only after creation — new columns are added but existing price columns are never overwritten — ensuring that the original exchange data remains intact for debugging and validation throughout the bot's execution.
The DataFrame index automatically represents trading time — you do not need to manage timestamps separately.
A DataFrame's default index is an integer sequence (0, 1, 2...) — not a timestamp — unless explicitly set to a datetime column. Using the default integer index in a trading bot is safer than a datetime index for backtesting because integer row access via `iloc[i]` is unambiguous regardless of any timestamp gaps or duplicate timestamps in the data. Timestamps are stored as a labelled column — `df['timestamp']` — and accessed explicitly when needed for logging or time-based filtering. Confusing the DataFrame index with trading time is a common source of subtle bugs in time series backtesting logic.