HwalDOCS

Trigger evaluation

Every call to tick_position reads the latest price from the configured feed, advances the trailing extreme, then evaluates three triggers in a fixed order. The first condition that hits settles the position in the same instruction.

Evaluation order

Triggers are checked in this order. The first hit wins. Set a value to 0 to disable that trigger.

  1. Stop loss stop_price
  2. Take profit take_profit_price
  3. Trailing trailing_offset + trailing_extreme

Long side conditions

text
stop:  price <= stop_price
tp:    price >= take_profit_price
trail: price <= trailing_extreme - trailing_offset
       where trailing_extreme = max(trailing_extreme, price)

On open and on every tick, the program updates trailing_extreme = the highest price seen so far. The trailing trigger fires when the price retraces from that extreme by exactly trailing_offset.

Short side conditions

text
stop:  price >= stop_price
tp:    price <= take_profit_price
trail: price >= trailing_extreme + trailing_offset
       where trailing_extreme = min(trailing_extreme, price)
Trailing extreme is initialized to entry
On open_position, the program sets trailing_extreme = entry_price. If price never moves favorably, the trailing condition does not fire spuriously. The extreme only advances on actual favorable movement.

Validation at open

The program rejects positions whose triggers are on the wrong side of entry. This prevents a position from auto-triggering on the next tick.

text
long  & stop_price > 0       requires stop_price < entry_price
long  & take_profit > 0      requires take_profit > entry_price
short & stop_price > 0       requires stop_price > entry_price
short & take_profit > 0      requires take_profit < entry_price
any   & trailing_offset > 0  requires trailing_offset < entry_price

Settlement split

When a trigger fires, the position's collateral is split inline:

  • fee = collateral × fee_bps ÷ 10_000 → fee receiver
  • keeper_reward = collateral × keeper_reward_bps ÷ 10_000 → tick caller
  • net_to_owner = collateral − fee − keeper_reward → position owner

Status flips to TRIGGERED, trigger_reason records which of the three fired, and settled_at is the slot clock.

Edge cases

  1. Stale feed If last_updated is older than 120 seconds, ticks revert with PriceFeedStale.
  2. Zero price Ticks revert with PriceFeedZero.
  3. Multiple triggers met same tick Stop wins over TP, TP wins over trailing.
  4. No trigger met The instruction succeeds, only tick_count and possibly trailing_extreme change.
  5. Trigger update mid-flight update_triggers resets trailing_extreme to entry if the offset changes.