Price data and bars¶
Read the current bar or earlier values to build a trading rule. A bar is one interval of price data.
Read a value¶
| Series | Value |
|---|---|
open[0], high[0], low[0], close[0] |
Current bar's prices. |
volume[0] |
Current bar's volume. |
timestamp[0] |
Current bar timestamp. |
close[1] |
Previous bar close. |
hl2[0] |
Average of current high and low. |
hlc3[0] |
Average of current high, low and close. |
[N] means N bars ago. Negative indices are not allowed. close is also callable: close() requests an exit; close[0] reads data.
Wait for enough history¶
def on_tick():
if len(close) < 20:
return
if position.is_flat and close[0] > mean(close, 20):
long(10)
Reading past available history raises a history error. A guard makes warmup explicit. Do not use future bars to decide a historical trade.
For another timeframe, len(security("SPY", "1h")) can guard unavailable
history only after timing is valid. Every read needs the current decision time
and datetime source timestamps with no nulls and compatible timezones. Missing
timing raises the essential TS-TF-NO-TIMESTAMP error, even in non-strict runs;
it is not an empty history or a false trading condition. Repair the source or
dispatch clock. See the hourly worked example
for which completed bar is visible, when a resulting order fills, and how an
async host keeps existing holdings managed while new decisions are blocked.
Use an indicator¶
Pass the series to a supported indicator, such as sma(close, 20). Many indicator results are series too, so [0] selects the current value. Check indicator usage before mixing scalars and series.
For exact available data functions, see the price-data reference.
Count the values you need¶
Index zero is the newest available bar. Reading close[1] needs at least two bars; reading close[20] needs at least 21. A full 20-bar window uses offsets 0 through 19. The current value is included in mean(close, 20) and highest(high, 20).
def on_tick():
if len(close) < 2:
return
price_is_rising = close[0] > close[1]
if position.is_flat and price_is_rising:
long(10)
len(close) reports the available dispatch history. History length does not prove every field is valid; price/volume inputs must also be appropriate for the selected instrument. A history error and a valid condition that returns false are different outcomes.
Bound a long run's memory¶
Set retention in the parameter dictionary returned by on_start():
def on_start():
return {"max_bar_history": 5000, "max_bars_per_symbol": {"TCS": 1000}}, {}
max_bar_history limits the shared observed-bar stream used by close and the
other price proxies. Its default is 200,000 feed bars. max_bars_per_symbol
optionally limits the per-symbol history lookup indexes; a positive integer
applies to every symbol, or a dictionary sets individual limits. Unspecified
symbols use the global limit. Limits must be positive integers, not booleans.
In this example get_historical_bars("TCS", 1500) can return at most the most
recent 1,000 retained TCS observations, while the shared stream can hold 5,000
feed bars. A request returns the observations available so far, never future
bars or an automatic rescan of the complete backtest. Size your limits for
indicator lookbacks and warmup, and check the returned length. Timeframe queries
prefer retained bars of that timeframe; when none exist they retain the
single-resolution fallback to the symbol's available bars. A fallback is not
timeframe aggregation: its BarSeries.timeframe reports the actual resolution,
not the missing requested one. Strict consumers such as security and sizing
reject a resolution mismatch. Mixed-resolution fallback data cannot be combined
into a falsely labeled series. For example, requesting 1d from a 1m-only
local stream still gives legacy history readers minute observations labeled
1m; it cannot supply a daily indicator or daily sizing history.
When supplying model Bar objects, pass the wrapper timestamp and mode. If the
dataframe also contains timestamps, they must agree with the wrapper's instant.
Each symbol has at most one row in a bar. Duplicate symbol rows or conflicting
times raise before execution instead of letting scalar reads silently select
one observation. Wrapper-only timestamps remain supported for existing feeds.
Bar.from_polars and CSV loading retain an optional timeframe column. Every
row in one timestamp group must have the same nonempty label, for example 1d.
Without that column, the existing 1m default remains; daily spacing alone does
not establish a daily availability contract. For a daily CSV, include
timestamp,symbol,open,high,low,close,volume,timeframe with 1d on each row,
then run atom run my_strategy.py --data daily.csv. The default synthetic CLI
stream is not a source of daily candles.
Prices, volume and full bars¶
hl2 and hlc3 are derived prices in the same units as close. ohlc4 averages open, high, low and close. Volume is a quantity field, not a price, and its unit depends on the data source. bars supplies the full OHLCV bundle for functions such as ATR that need more than one price series.
In explicit multi-symbol context, select the series you mean, for example close["TCS"][0], instead of relying on an ambiguous bare close. For a second symbol or timeframe, use security and its separate history window. A daily history window does not count intraday bars.
When constructing a model BarSeries, an explicit portfolio mode stays a portfolio
even with one remaining symbol. Integrations can therefore preserve a dictionary
of per-symbol results as the universe shrinks. Multiple symbols require portfolio
mode. Choose Mode.SINGLE explicitly when one symbol should return a scalar or
one series rather than a per-symbol dictionary. Previously a one-symbol
Mode.PORTFOLIO construction was silently collapsed to single mode.
See Alpha Lab inputs for its ordered
history requirements and single-versus-portfolio result shapes.
In a local backtest, an explicit list request such as
get_historical_bars(["TCS", "INFY"], 100, timeframe="1d") returns up to 100
observed bars per available instrument. Import the helper from
atom.helpers.historical when using it explicitly. It retains portfolio mode for
a one-name list, omits names without history and returns None if no requested
name has data. It does not fill gaps or manufacture a shared trading calendar.
Raw and adjusted model data¶
Model Bar and BarSeries default to adjusted=False. Set adjusted=True
only when the supplied prices already include the data provider's split or
dividend adjustments; the flag does not adjust prices itself. Symbol extraction,
resampling and local historical queries preserve it. Combining raw and adjusted
observations raises rather than silently treating them as one price history.
For example, an adjusted portfolio history extracted with history["TCS"]
still reports adjusted=True, with unchanged TCS prices. Resampling that child
to five minutes retains the same flag. Before 4.11.0, extraction and local
history could incorrectly report those numbers as raw; rebuild affected inputs.
Model field lists are chronological, unlike injected close[0], which is newest.
They are detached views of the current dataframe. Changing a returned list does
not change the model; replacing history.df or editing its columns changes the
next property read. Keep symbols, timestamp, timeframe and mode consistent with
the replacement frame: mutation does not rerun construction validation.
For instance, after reading values = history.close, changing values[-1]
does not edit prices. To transform prices deliberately, replace the appropriate
dataframe column and read history.close again. The old persistent property
cache could return stale numbers after that replacement; 4.11.0 no longer does.
Editor declarations¶
atom-stubs.pyi is the canonical declaration file for injected names. Its types
include callable close, explicit symbol selection and datetime timestamps.
An editor cannot infer bare globals simply from an arbitrarily named file beside
a strategy. A standalone checker can expose this file as atom_vocab.pyi in its
configured stub path and use a typing.TYPE_CHECKING-only import of those names;
the runtime still supplies the real globals. Host editors may integrate the same
declarations directly. close() can return None when it closes a portfolio;
do not use that return value as confirmation of fills.