- OpenBacktesting
- Market data, timeframes, and instruments
Market data, timeframes, and instruments¶
Backtest accepts a pandas DataFrame for one asset. Load and clean your data before constructing the backtest.
Timeframe · TimeframeUnit · DataContext · InstrumentSpec
Load a CSV¶
import pandas as pd
data = pd.read_csv("prices.csv", parse_dates=["Date"], index_col="Date")
data = data.sort_index()
data = data[["Open", "High", "Low", "Close", "Volume"]]
The CSV is your input file. For a ready-to-run alternative, use from openbacktesting.test import GOOG and data = GOOG.copy().
| Requirement | Reason |
|---|---|
Exact column names Open, High, Low, Close |
The broker reads these prices. Add Volume for volume indicators. |
| Finite, positive OHLC; valid high/low ranges | Orders cannot be matched against missing or invalid prices. |
| Increasing, unique index | Each row represents one bar in chronological order. A DatetimeIndex gives meaningful timestamps and calendar statistics. |
| Extra numeric columns allowed | Access them with self.data.MyColumn or bind by name to indicators. |
| No mutation after indicator registration | Preprocess before the run so indicators and execution use consistent prices. |
Read data inside a strategy¶
self.open, high, low, close, and volume are read-only handles. self.hl2=(H+L)/2, self.hlc3=(H+L+C)/3, and self.hlcc4=(H+L+2*C)/4. During next(), [-1] means the current bar and [-2] the previous bar. During init(), the full input history is visible.
Save handles such as self.saved_close = self.close to keep following the bar cursor. .s, .df, and numpy.asarray(handle) produce snapshots of currently visible data; a saved pandas object does not grow on later bars. Arithmetic also produces ordinary arrays. Register calculations through self.ind if they must be read through a handle.
self.data_index is the visible index; self.df exposes the visible data table. self.pip is a data-derived estimate, not an exchange tick rule.
Specify timeframe and timezone¶
from openbacktesting import DataContext, Timeframe
from openbacktesting.test import GOOG
data = GOOG.copy()
data.index = data.index.tz_localize("America/New_York")
context = DataContext(Timeframe.days(1), "America/New_York")
Pass context=context to Backtest, or to runtime.run where it is required. The index must be timezone-aware. The context converts display timezones while preserving instants; it does not resample bars. Use the actual timeframe of your input data. self.timeframe is None if no context is supplied.
Construct intervals with Timeframe.seconds/minutes/hours/days/weeks/months(multiplier). Multipliers are positive integers; months are calendar intervals, not a fixed number of seconds. TimeframeUnit supplies the corresponding enum values when constructing Timeframe(unit, multiplier) directly.
Timeframe¶
Timeframe value; the host validates data-source support, and not all combinations are guaranteed to have market data.
| Attribute | Type | Meaning |
|---|---|---|
unit |
TimeframeUnit |
TimeframeUnit for this interval. |
multiplier |
int |
Positive integer count of timeframe units. |
Timeframe.seconds¶
Create a seconds timeframe.
Timeframe.snapshot¶
Return independent plain unit/multiplier values.
Timeframe.hours¶
Normalize hours to minutes; 24 hours is not a daily timeframe.
Timeframe.days¶
Create a calendar-day timeframe.
Timeframe.minutes¶
Create a minutes timeframe.
Timeframe.weeks¶
Create a calendar-week timeframe.
Timeframe.months¶
Create a calendar-month timeframe.
TimeframeUnit¶
Time-bar units; calendar units are not implicitly converted to fixed seconds.
| Member | Value |
|---|---|
TimeframeUnit.SECOND |
second |
TimeframeUnit.MINUTE |
minute |
TimeframeUnit.DAY |
day |
TimeframeUnit.WEEK |
week |
TimeframeUnit.MONTH |
month |
DataContext¶
Describe the existing market-data timeframe and shared timezone for charts, strategy calendars, and statistics.
| Attribute | Type | Meaning |
|---|---|---|
timeframe |
Timeframe |
Declared Timeframe of the supplied bars. |
timezone |
str |
Timezone used to display/group aware timestamps. |
DataContext.snapshot¶
Return independent plain values without reusing mutable request objects.
Specify asset quantity and price rules¶
from openbacktesting.broker import InstrumentSpec
instrument = InstrumentSpec(symbol="ASSET", currency="USD",
quantity_step=0.001, min_quantity=0.001,
min_notional=5, price_tick=0.01)
Pass instrument=instrument to the run. qty=0.1 remains one tenth of a unit; prices and indicators are not scaled. Defaults use whole units (quantity_step=1), minimum quantity equal to the step, no price tick, and no minimum notional. Direct quantities and all supplied prices must match configured grids; budget-based sizing can round quantity toward zero. Price grids also apply to OHLC data. Labels do not perform currency conversion.
With an explicit price_tick, use instrument.round_price_to_tick(price) to obtain a grid-aligned price before setting protection. quantity(value, floor=True) can round units; validate_data(frame) checks the data against instrument rules.
InstrumentSpec¶
broker.InstrumentSpec(
symbol='asset',
quantity_step=1,
min_quantity=None,
price_tick=None,
min_notional=0,
currency=None,
)
Actual asset quantity and price grids; currency is only a label.
InstrumentSpec.price¶
Validate requested prices strictly; normalize execution prices in the adverse direction.
InstrumentSpec.quantity¶
Direct requests must lie on the grid; budgeted quantities may round toward zero.
InstrumentSpec.validate_data¶
Trading market data must be ordered, unique, and have valid prices; explicit ticks must not be silently corrected.
InstrumentSpec.round_price_to_tick¶
Round prices to the nearest explicit tick; half ticks round to the higher price.