דלגו לתוכן
פתיחת RaamTrade

RC2_TIMEZONE_UNKNOWN

תוכן זה אינו זמין עדיין בשפה שלך.

astimezone(...) needs exactly one IANA timezone string literal, and must be chained straight to .hour, .minute, .month, or .weekday().

What it means

self.trade.timestamp.astimezone("<IANA>") re-expresses the bar’s timestamp in another region’s wall clock. Three rules make it checkable at compile time rather than at bar 40,000 of a backtest:

  • One argument, an IANA id, as a literal. The id is validated while you type, so "America/New_York" compiles and a typo does not.
  • No bare astimezone(). In Python that means “the machine’s local timezone” — which on a server is a property of the deployment, not of the strategy. A strategy whose entries move when it is scheduled onto a different node is not a strategy.
  • Chained, not stored. astimezone(...) is an access path, not a value: it must be followed immediately by .hour, .minute, .month, or .weekday().

Why it happens

A near-miss on the zone id — underscores and exact spelling matter:

class WrongZone(Strategy):
trade = Symbol()
sizing = FixedCapital()
def execute(self):
if self.trade.timestamp.astimezone("America/New York").hour >= 10 and self.trade.is_flat:
self.buy(self.trade)

Python’s no-argument form, meaning “local time”:

class LocalTime(Strategy):
trade = Symbol()
sizing = FixedCapital()
def execute(self):
if self.trade.timestamp.astimezone().hour >= 10 and self.trade.is_flat:
self.buy(self.trade)

Or the converted time saved to a variable to be reused — the natural refactor, and the one the language doesn’t allow:

class StoredZone(Strategy):
trade = Symbol()
sizing = FixedCapital()
def execute(self):
ny_now = self.trade.timestamp.astimezone("America/New_York")
if ny_now.hour >= 10 and self.trade.is_flat:
self.buy(self.trade)

Passing the zone through a variable (zone = "America/New_York" … astimezone(zone)) is refused for the same reason: a variable defeats the compile-time check.

How to fix it

Write the id as a literal and read the field off the end of the chain. Repeat the chain if you need two fields — it is a path, and paths are cheap.

class SessionClock(Strategy):
trade = Symbol()
sizing = FixedCapital()
def execute(self):
ny_hour = self.trade.timestamp.astimezone("America/New_York").hour
if ny_hour >= 10 and self.trade.timestamp.weekday() < 5 and self.trade.is_flat:
self.buy(self.trade)

The field can be stored in a local (ny_hour above is an ordinary number); only the conversion itself cannot.

If all you need is the bar’s own clock, you don’t need astimezone at all — self.trade.timestamp is already expressed in the slot’s session timezone:

class SessionLocal(Strategy):
trade = Symbol(session=USEquityHourly)
sizing = FixedCapital()
def execute(self):
if self.trade.timestamp.hour >= 10 and self.trade.is_flat:
self.buy(self.trade)

It costs you the fast path

astimezone (like value_at) drops a strategy off the analyzed graph path onto the slower passthrough one. Reading the slot’s own day or month with self.trade.timestamp.weekday() or self.trade.timestamp.month does not — it keeps the fast path. That is invisible in a single backtest and very visible in an optimization or a walk-forward run — worth knowing before you reach for it in a hot condition.