# Market data, timeframes, and instruments



`Backtest` accepts a pandas DataFrame for one asset. Load and clean your data before constructing the backtest.

[Timeframe](https://docs.openbacktesting.com/reference/data/#openbacktesting-timeframe) · [TimeframeUnit](https://docs.openbacktesting.com/reference/data/#openbacktesting-timeframeunit) · [DataContext](https://docs.openbacktesting.com/reference/data/#openbacktesting-datacontext) · [InstrumentSpec](https://docs.openbacktesting.com/reference/data/#openbacktesting-broker-instrumentspec)

## Load a CSV

```python
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

```python
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.

<a id="openbacktesting-timeframe"></a>



## Timeframe

```python
Timeframe(unit, multiplier)
```

Timeframe value; the host validates data-source support, and not all combinations are guaranteed to have market data.

| Attribute | Type | Meaning |
| --- | --- | --- |
| <a id="openbacktesting-timeframe-unit"></a>`unit` | `TimeframeUnit` | TimeframeUnit for this interval. |
| <a id="openbacktesting-timeframe-multiplier"></a>`multiplier` | `int` | Positive integer count of timeframe units. |

<a id="openbacktesting-timeframe-seconds"></a>



### Timeframe.seconds

```python
Timeframe.seconds(value)
```

Create a seconds timeframe.

<a id="openbacktesting-timeframe-snapshot"></a>



### Timeframe.snapshot

```python
Timeframe.snapshot()
```

Return independent plain unit/multiplier values.

<a id="openbacktesting-timeframe-hours"></a>



### Timeframe.hours

```python
Timeframe.hours(value)
```

Normalize hours to minutes; 24 hours is not a daily timeframe.

<a id="openbacktesting-timeframe-days"></a>



### Timeframe.days

```python
Timeframe.days(value)
```

Create a calendar-day timeframe.

<a id="openbacktesting-timeframe-minutes"></a>



### Timeframe.minutes

```python
Timeframe.minutes(value)
```

Create a minutes timeframe.

<a id="openbacktesting-timeframe-weeks"></a>



### Timeframe.weeks

```python
Timeframe.weeks(value)
```

Create a calendar-week timeframe.

<a id="openbacktesting-timeframe-months"></a>



### Timeframe.months

```python
Timeframe.months(value)
```

Create a calendar-month timeframe.

<a id="openbacktesting-timeframeunit"></a>



## 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` |

<a id="openbacktesting-timeframeunit-second"></a>


<a id="openbacktesting-timeframeunit-minute"></a>


<a id="openbacktesting-timeframeunit-day"></a>


<a id="openbacktesting-timeframeunit-week"></a>


<a id="openbacktesting-timeframeunit-month"></a>



<a id="openbacktesting-datacontext"></a>



## DataContext

```python
DataContext(timeframe, timezone)
```

Describe the existing market-data timeframe and shared timezone for charts, strategy calendars, and statistics.

| Attribute | Type | Meaning |
| --- | --- | --- |
| <a id="openbacktesting-datacontext-timeframe"></a>`timeframe` | `Timeframe` | Declared Timeframe of the supplied bars. |
| <a id="openbacktesting-datacontext-timezone"></a>`timezone` | `str` | Timezone used to display/group aware timestamps. |

<a id="openbacktesting-datacontext-snapshot"></a>



### DataContext.snapshot

```python
DataContext.snapshot()
```

Return independent plain values without reusing mutable request objects.

## Specify asset quantity and price rules

```python
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.

<a id="openbacktesting-broker-instrumentspec"></a>



## InstrumentSpec

```python
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.

| Attribute | Type | Meaning |
| --- | --- | --- |
| <a id="openbacktesting-broker-instrumentspec-symbol"></a>`symbol` | `str` | Asset label; does not fetch market data. |
| <a id="openbacktesting-broker-instrumentspec-quantity-step"></a>`quantity_step` | `float` | Minimum increment in asset units. |
| <a id="openbacktesting-broker-instrumentspec-min-quantity"></a>`min_quantity` | `float \| None` | Minimum quantity for opening exposure. |
| <a id="openbacktesting-broker-instrumentspec-price-tick"></a>`price_tick` | `float \| None` | Optional price increment; None leaves prices ungridded. |
| <a id="openbacktesting-broker-instrumentspec-min-notional"></a>`min_notional` | `float` | Minimum opening notional in settlement currency. |
| <a id="openbacktesting-broker-instrumentspec-currency"></a>`currency` | `str \| None` | Settlement-currency label; no exchange-rate conversion. |

<a id="openbacktesting-broker-instrumentspec-price"></a>



### InstrumentSpec.price

```python
InstrumentSpec.price(value, *, side=None)
```

Validate requested prices strictly; normalize execution prices in the adverse direction.

<a id="openbacktesting-broker-instrumentspec-quantity"></a>



### InstrumentSpec.quantity

```python
InstrumentSpec.quantity(value, *, floor=False, opening=True)
```

Direct requests must lie on the grid; budgeted quantities may round toward zero.

<a id="openbacktesting-broker-instrumentspec-validate-data"></a>



### InstrumentSpec.validate_data

```python
InstrumentSpec.validate_data(frame)
```

Trading market data must be ordered, unique, and have valid prices; explicit ticks must not be silently corrected.

<a id="openbacktesting-broker-instrumentspec-round-price-to-tick"></a>



### InstrumentSpec.round_price_to_tick

```python
InstrumentSpec.round_price_to_tick(value)
```

Round prices to the nearest explicit tick; half ticks round to the higher price.

[Backtest](https://docs.openbacktesting.com/reference/core/index.md) · [Indicator handles](https://docs.openbacktesting.com/reference/indicator-api/index.md) · [User manual](https://docs.openbacktesting.com/index.md)
