Skip to content
Open RaamTrade

RC2_STATE_TYPE_REASSIGN

self.<name> was first assigned as <type> on line N, but reassigned to <other type> here. Persistent state types are fixed at first assignment.

What it means

A persistent-state slot gets its type from its first assignment, and keeps it for the life of the strategy. The slot is a real typed field in the generated code — there is no boxing step where an int slot could quietly start holding a decimal.

The diagnostic names the line of the first assignment, which is usually the faster way to see what happened than reading the line it fired on.

Why it happens

class Bad(Strategy):
trade = Symbol()
sizing = FixedCapital()
def execute(self):
self.level = 0 # first assignment → int
self.level = 1.5 # ❌ decimal into an int slot

The most common real shape is subtler: a counter seeded with 0 that later takes a price — or the position, which is a decimal too (self.trade.position).

How to fix it

Decide the type once and write every assignment in it. If the slot ever holds a price, seed it as a decimal (0.0, not 0):

class Good(Strategy):
trade = Symbol()
sizing = FixedCapital()
level = 0.0 # class-body declaration pins the type up front
def execute(self):
if self.trade.is_flat:
self.level = self.trade.close # ✅ decimal throughout
self.buy(self.trade)

The other direction is not an error: a whole number into a decimal slot is stored as a decimal, so resetting with 0 is fine once the slot is 0.0:

class Reset(Strategy):
trade = Symbol()
sizing = FixedCapital()
last_qty = 0.0
def execute(self):
if self.trade.is_flat:
self.last_qty = 0 # ✅ stored as 0.0
self.buy(self.trade)
else:
self.last_qty = self.trade.position

If the two uses are genuinely different things, they deserve two slots:

class TwoSlots(Strategy):
trade = Symbol()
sizing = FixedCapital()
entry_count = 0 # int
entry_price = 0.0 # decimal
def execute(self):
if self.trade.is_flat:
self.entry_count += 1
self.entry_price = self.trade.close
self.buy(self.trade)