Skip to content
Open RaamTrade

RC2_HELPER_STATE_WRITE

Helper methods cannot rebind scalar persistent state — self.<name> = ... doesn’t propagate back to the caller.

What it means

A helper reads persistent state freely. What it cannot do is rebind a scalar slot: state is threaded through helpers by value, so self.session_high = … inside a helper would update a copy and be discarded the moment the helper returns. Rather than let a write silently vanish on a real-money strategy, the transpiler refuses it.

Index and key writes into a class-body list or dict are a different story — those mutate the object the slot already points at, which both sides share, so the change survives the return and is allowed.

Why it happens

The slot lives on the strategy, and the update ended up inside the helper:

class Bad(Strategy):
trade = Symbol()
sizing = FixedCapital()
session_high = 0.0
def execute(self):
self.track_high()
if self.trade.close > self.session_high and self.trade.is_flat:
self.buy(self.trade)
def track_high(self):
self.session_high = self.trade.high # ❌ scalar rebind inside a helper
return 0

self.session_high += 1 inside a helper is refused for the same reason and reports the same code.

How to fix it

Have the helper return the new value and let execute() do the assignment. The helper stays a calculation; the write stays in one place.

class Good(Strategy):
trade = Symbol()
sizing = FixedCapital()
session_high = 0.0
def execute(self):
self.session_high = self.next_session_high() # ✅ the write happens in execute()
if self.trade.close > self.session_high * 0.99 and self.trade.is_flat:
self.buy(self.trade)
def next_session_high(self):
if self.trade.high > self.session_high:
return self.trade.high # ✅ reading state is fine
return self.session_high

A helper returns a decimal, so keep the slot it feeds declared as a decimal (session_high = 0.0, not = 0) — a slot’s type is fixed by its first assignment, and mixing the two is RC2_STATE_TYPE_REASSIGN.

Collections are the exception

A class-body list or dict is written through a shared reference, so a helper may mutate it by index or key:

class HelperWrites(Strategy):
trade = Symbol()
sizing = FixedCapital()
session_highs = [0.0]*5
counts = {"up": 0, "down": 0}
def execute(self):
self.update_extremes()
if self.trade.close > self.session_highs[0] and self.trade.is_flat:
self.buy(self.trade)
def update_extremes(self):
if self.trade.high > self.session_highs[0]:
self.session_highs[0] = self.trade.high # ✅ index write — propagates
self.counts["up"] += 1 # ✅ key write — propagates
return 0

The rule in one line: a helper may change what a slot points at the inside of, never what the slot points at.