Strategy API reference
Every function: orders, positions, series, indicators, FVGs, news() and near_news().
The complete reference of the talios package: everything your strategy can read and call. Two imports cover it all.
from talios import Strategy, Long, Short
from talios.indicators import ema, sma, rsi, atr, highest, lowest, crossover, crossunder, fvg, killzone, session, news, near_newsStrategy
| Name | What it is |
|---|---|
setup(self) | Optional. Once per pair, before the first bar. |
on_bar(self, bar) | Required. At each bar's close. Without it, the run stops with "define on_bar(self, bar) in your Strategy". |
self.data | The pair's price series (see Series). |
self.pair | The pair being run, e.g. "EUR/USD". |
self.timeframe | The backtest timeframe, e.g. "1H". |
self.minutes | The bar length in minutes (60 on 1H). |
self.position | The open Position, or None. |
self.order | The pending Order, or None. |
self.trades | The pair's closed trades so far (a list of Trade). |
cost_r = 0.0 | Class attribute: R taken off every trade to account for spread and commission (0 or more). Without it, trades are costless. |
| Parameters | Any other class attribute holding a number, string or boolean (up to 50). |
Talios creates one fresh instance of your class per pair, so state kept on self never leaks from one pair to the next.
Series and Bar
| Name | What it is |
|---|---|
self.data.open / .high / .low / .close / .volume | Lists of the same length, oldest first. |
self.data.time | Each bar's open time, in epoch seconds UTC. |
self.data.killzone / .session | One label per bar (or None), handy to precompute filters in setup. |
len(self.data), self.data[i] | The number of bars, and the Bar at index i (negative indexes and slices work). |
bar.i | The bar's index in the series. |
bar.time / bar.dt | Its open time, in epoch seconds UTC / as a UTC datetime. |
bar.local | Its open time on the project's timezone, summer and winter time included: bar.local.hour == 9 is 9:00 your time all year. local(t) in talios.indicators does the same for any time. |
bar.open / .high / .low / .close / .volume | Its prices and volume. |
bar.pair / .killzone / .session | Its pair, killzone and session. |
Never read the future
The whole series is inself.data so indicators can be computed once in setup. Inside on_bar, only read indexes up to bar.i: anything above is look-ahead, and makes results that can't be traded.Orders and positions
One position at a time per pair, and at most one pending order. Long and Short are the strings "Long" and "Short".
self.enter(direction, stop, target=None, rr=None, price=None, expiry=None, note=None)
| Argument | Meaning |
|---|---|
| direction | Long or Short. |
| stop | Required. The stop loss price. |
| target / rr | The take profit, as a price (target) or as a multiple of the risk measured from the fill (rr). Give one or neither, never both. With neither, the trade ends on its stop, on exit() or at the end of the data. |
| price | None: a market order, filled at the next bar's open. A price: an order working from the next bar. For a Long, at or below the signal bar's close it is a limit (fills when a low reaches it), above it a stop entry (fills when a high reaches it); the reverse for a Short. It fills at its price, or at the open when a bar opens past it. |
| expiry | How many bars a price order stays working (a whole number, 1 or more). None: until it fills, is cancelled or replaced. |
| note | A text up to 200 characters, carried to the trade. |
Returns True when the order is placed. It is refused, with a note in the console and False, when a position is already open, when the stop or the target is on the wrong side of the entry (the order's price, or this bar's close for a market order), or when rr is not above 0. A new enter replaces a pending order. An order whose fill lands past its stop or target is cancelled: the setup is gone.
| Call | What it does |
|---|---|
self.cancel() | Drops the pending order. |
self.exit(note=None) | Closes the position at this bar's close. False when there is none. |
self.move_stop(price) | Moves the open position's stop (break-even, trailing). R stays measured on the initial stop. |
self.move_target(price) | Moves the target; move_target(None) removes it. |
# Market order: filled at the next bar's open, stop at a price, target at 2R
self.enter(Long, stop=bar.low, rr=2)
# Limit order at 1.0850, valid for 5 bars, fixed target price
self.enter(Long, stop=1.0820, target=1.0920, price=1.0850, expiry=5)
# Break-even once the trade is 1R in profit
pos = self.position
if pos and pos.r(bar.close) >= 1:
self.move_stop(pos.entry)
# Time exit
if pos and pos.bars(bar) >= 24:
self.exit("time")Position, Order and Trade
| Object | Fields |
|---|---|
| Position (self.position) | .direction, .entry (fill price), .stop, .target, .initial_stop, .entry_i, .entry_time, .risk (the price distance of 1R), .note, .r(price) (R at that price, before cost_r), .bars(bar) (bars held, 0 on the fill bar). |
| Order (self.order) | .direction, .price, .stop, .target, .rr, .placed_i, .expiry, .note, .kind ("market", "limit" or "stop"). |
| Trade (self.trades) | .direction, .entry, .exit, .r, .entry_i, .exit_i, .entry_time, .exit_time, .initial_stop, .stop, .target, .reason ("stop", "target", "exit" or "end"), .open, .note, .mae (how far it went against you, in R). |
talios.indicators
Every indicator only uses bars up to the one it is computed for, and returns a list as long as its input, with None while it warms up. A list argument can also be the series itself (its closes are used).
| Function | Returns |
|---|---|
ema(values, n) | Exponential moving average (starts from the average of the first n values). |
sma(values, n) | Simple moving average. |
rsi(values, n=14) | Wilder's RSI, 0 to 100. |
atr(data, n=14) | Wilder's average true range. Takes the series (self.data), not a list. |
highest(values, n), lowest(values, n) | Rolling max / min over the last n values, the current one included. |
crossover(a, b, i), crossunder(a, b, i) | True when list a crosses above / below b (a list or a number) at index i (or at a Bar). |
fvg(data, min_size=0.0, max_age=None) | The series' fair value gaps, exactly as on the Afterburner chart (see below). |
killzone(bar) | The killzone the bar opens in, from your own chart Killzone settings (Paris time; by default "Asia" 02:00–06:00, "London" 08:00–11:00, "NY" 13:00–16:00), or None. |
session(bar) | The journal's session of the bar's open, in UTC: "Asia" (00–07), "London" (07–12), "Overlap" (12–16), "New York" (16–21) or "Off Hours". |
news(pair=None, impact="high") | The economic calendar releases of the backtest period that move the pair's currencies, sorted by time (see below). |
near_news(bar, minutes=30, impact="high", pair=None) | True when a release of that impact falls within minutes before or after the bar's open (edges included). |
Fair value gaps
A gap is bullish when bar i's low is above bar i−2's high, bearish when bar i's high is below bar i−2's low. min_size is a minimum height in price; max_age drops an untouched gap after that many bars. fvg() returns a Gaps object:
gaps.formed_at(i): the gaps completed at bar i.gaps.active(i): the gaps formed before i and not touched yet, newest last.gaps.first_touch(bar): the oldest active gap this bar trades back into (then marked touched), or None. A gap counts once.- A Gap has
.bullish,.bearish,.top,.bottom,.height,.mid,.formed(index of its third bar),.timeand.touched(index or None).
News functions
Talios strategies read the same economic calendar as the News indicator of your charts (13 countries, since 2020). impact is "high", "medium", "low" or a list of them. A release counts for a pair when it moves one of its currencies: gold and the US indices follow USD, GER40 follows EUR, and so on.
news()returns a list of releases, each with.time(epoch seconds UTC),.dt,.title,.currency,.countryand.impact. It builds a new list each call: call it once insetupand keep it.near_news()answers the usual question directly: is this bar too close to a release?
from talios import Strategy, Long, Short
from talios.indicators import ema, near_news, news
class TrendNoNews(Strategy):
"""EMA 50 / 200 trend, sitting out 30 min around high-impact news."""
news_window = 30 # minutes before and after a release
def setup(self):
self.fast = ema(self.data.close, 50)
self.slow = ema(self.data.close, 200)
self.releases = news(impact="high") # once, in setup
print(len(self.releases), "high-impact releases for", self.pair)
def on_bar(self, bar):
i = bar.i
if self.position or self.slow[i] is None:
return
if near_news(bar, minutes=self.news_window, impact="high"):
return
if self.fast[i] > self.slow[i] and bar.close > self.fast[i]:
self.enter(Long, stop=bar.low, rr=2)
elif self.fast[i] < self.slow[i] and bar.close < self.fast[i]:
self.enter(Short, stop=bar.high, rr=2)Also importable
Bar, Series, Position, Order, Trade from talios; Gap, Gaps, NewsEvent from talios.indicators. Useful for type hints in your own helper files.