OHLCV Access
תוכן זה אינו זמין עדיין בשפה שלך.
Every declared Symbol() exposes the current bar’s price data:
self.trade.close # current bar closeself.trade.open # current bar openself.trade.high # current bar highself.trade.low # current bar lowself.trade.volume # current bar volumeAll return decimal (financial precision — never float).
OHLCV access works on any symbol slot — trading symbol or data feed.
class SPYFiltered(Strategy): trade = Symbol(session=USEquityDaily, trade=True) spy = Symbol(ticker="SPY") sizing = FixedCapital()
def execute(self): if self.spy.close > self.spy.open and self.trade.is_flat: self.buy(self.trade)Using OHLCV in indicators
Pass an OHLCV field as the on= argument to compute an indicator on something other than close:
high_sma = SMA(20, on=self.trade.high)low_ema = EMA(10, on=self.trade.low)vol_sma = SMA(30, on=self.trade.volume)Bar time
Every symbol slot also exposes the current bar’s timestamp, expressed in that symbol’s session timezone:
self.trade.timestamp.hour # 0–23, in the session's timezoneself.trade.timestamp.minute # 0–59self.trade.timestamp.weekday() # Monday = 0 … Sunday = 6 (Python's weekday())self.trade.timestamp.month # January = 1 … December = 12 (Python's month)A symbol bound to a New York session reads New York wall-clock time; a symbol on a Tel Aviv session reads Israel time. Daylight-saving transitions are handled per bar — “9:30 New York” means 9:30 in New York in January and July alike.
The month follows the same clock: a New York bar at 19:00 on 31 January reads
1 (January), even though that instant is already 1 February in UTC. Like
.hour, .month is a field, written without parentheses. Each symbol reads its
own bar, so a daily symbol keeps the month of its latest daily bar until the next
one arrives.
class SkipFebruary(Strategy): trade = Symbol() skip_month = Param(2, min=0, max=12) # 0 skips nothing sizing = FixedCapital()
def execute(self): fast = SMA(10, on=self.trade) slow = SMA(30, on=self.trade) month = self.trade.timestamp.month
if month == self.skip_month and self.trade.is_long: self.sell(self.trade, self.trade.position)
if month != self.skip_month and fast.crossed_above(slow) and self.trade.is_flat: self.buy(self.trade)class MorningOnly(Strategy): trade = Symbol() sizing = FixedCapital()
def execute(self): t = self.trade.timestamp.hour * 60 + self.trade.timestamp.minute in_ny_morning = t >= 570 and t < 660 # 09:30–11:00, session-local
if in_ny_morning and self.trade.is_flat: self.buy(self.trade)Reading another region’s clock
astimezone(...) re-expresses the same instant in another timezone — Python’s
datetime.astimezone, taking an IANA timezone name:
self.trade.timestamp.astimezone("Asia/Jerusalem").hourself.trade.timestamp.astimezone("America/Chicago").weekday()self.trade.timestamp.astimezone("Asia/Tokyo").monthThe timezone must be a string literal — a typo like "Asia/Jerusalm" fails the
compile with RC2_TIMEZONE_UNKNOWN, never a running backtest. astimezone(...)
is an access path, not a value: chain it directly to .hour, .minute,
.month, or .weekday() rather than storing it in a variable. Python’s no-argument
astimezone() (machine-local time) is not supported.
“Current bar” — what does it mean?
self.trade.close always returns the closed bar’s value. By the time execute() runs, the bar has finished forming — its OHLC are final.
For values from earlier bars, you need an indicator. There is no self.trade.close_at(1) for direct historical access — wrap with SMA(1), EMA(1), or a custom indicator using Series:
yesterday = SMA(1, on=self.trade.close).value_at(1)This is intentional. Direct historical-price arrays would let strategies snapshot arbitrary windows, which complicates the determinism story (warmup, walk-forward, live replay). Indicators encapsulate “look back N bars” with explicit warmup semantics.