RC2_EXIT_UNIT
Each number on an exit rule takes exactly one unit: a bare positional value (percent), or
percent=,points=,price=.break_evenhas noprice=;trailing_stopnames its two numbers instead.
What it means
On an exit rule, the keyword is the unit — the way timedelta(days=…) works. percent= (or a bare positional) is a percentage from entry, points= is a distance in price units from entry, price= is an absolute level that ignores the entry price entirely. One threshold, one unit; the transpiler refuses a stale spelling, a second unit, or a unit that doesn’t exist for the rule you called.
Two rules differ:
self.break_even()is measured from the entry, so it takes a percent orpoints=, andprice=is refused.self.trailing_stop()has two numbers, and each one names its own unit:activate_percent=oractivate_points=, thentrail_percent=ortrail_points=. A barepoints=orprice=doesn’t say which of the two numbers it means, so it is refused. Giving the same number two units (trail_percent=andtrail_points=) is refused too.
Why it happens
An abbreviation or an older spelling — pct=, pts=, unit=, dollars= are all called out by name so the message can teach the right one:
class StaleKeyword(Strategy): trade = Symbol() sizing = FixedCapital()
def execute(self): self.stop_loss(pct=2.0) if self.trade.is_flat: self.buy(self.trade)Two units in one call — usually a bare positional left behind when a keyword was added:
class TwoUnits(Strategy): trade = Symbol() sizing = FixedCapital()
def execute(self): self.stop_loss(2.0, points=5) if self.trade.is_flat: self.buy(self.trade)And a points-based trail spelled with the threshold keyword, which doesn’t say whether 5 points is the activation or the distance:
class PointsTrail(Strategy): trade = Symbol() sizing = FixedCapital()
def execute(self): self.trailing_stop(points=5) if self.trade.is_flat: self.buy(self.trade)A break-even at a fixed price. Break-even is always the entry price, and its number is how far up the trade must be first:
class PriceBreakEven(Strategy): trade = Symbol() sizing = FixedCapital()
def execute(self): self.break_even(price=450.0) if self.trade.is_flat: self.buy(self.trade)How to fix it
Pick the unit that matches what you actually mean, and give it once.
class Units(Strategy): trade = Symbol() sizing = FixedCapital()
def execute(self): self.stop_loss(points=5) # 5 price points below entry (long) self.take_profit(price=450.0) # absolute level, entry-independent self.break_even(points=20) # once up 20 points, a stop at entry self.trailing_stop(activate_points=20, trail_points=10) # from +20 points, trail 10 points if self.trade.is_flat: self.buy(self.trade)A bare positional is always percent, so self.stop_loss(2.0) and self.stop_loss(percent=2.0) are the same rule. Dollar-denominated thresholds are not a unit yet — express them as points or as a price level.
Related
- Exit Rules
RC2_EXIT_ARG— no threshold at all, or more positional values than the rule takes.RC2_TRAILING_TWO_NUMBERS—trailing_stopwith only one number.RC2_EXIT_NO_KWARGS— the exit verbs, where kwargs are the thing that isn’t allowed.