<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.spiretrading.com/index.php?action=history&amp;feed=atom&amp;title=State_Machine_Implementation</id>
	<title>State Machine Implementation - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.spiretrading.com/index.php?action=history&amp;feed=atom&amp;title=State_Machine_Implementation"/>
	<link rel="alternate" type="text/html" href="https://wiki.spiretrading.com/index.php?title=State_Machine_Implementation&amp;action=history"/>
	<updated>2026-07-28T17:52:32Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.34.1</generator>
	<entry>
		<id>https://wiki.spiretrading.com/index.php?title=State_Machine_Implementation&amp;diff=216&amp;oldid=prev</id>
		<title>Kamal: Created page with &quot;Once a state machine specification has been designed, its Python implementation is a mostly mechanical transcription. Every state, event, and condition in the code points back...&quot;</title>
		<link rel="alternate" type="text/html" href="https://wiki.spiretrading.com/index.php?title=State_Machine_Implementation&amp;diff=216&amp;oldid=prev"/>
		<updated>2026-07-13T18:34:35Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;Once a state machine specification has been designed, its Python implementation is a mostly mechanical transcription. Every state, event, and condition in the code points back...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;Once a state machine specification has been designed, its Python implementation&lt;br /&gt;
is a mostly mechanical transcription. Every state, event, and condition in the&lt;br /&gt;
code points back to a counterpart in the specification, and nothing appears in&lt;br /&gt;
the code that the specification doesn't call for.&lt;br /&gt;
&lt;br /&gt;
This article defines the transcription. It assumes familiarity with&lt;br /&gt;
[[State Machine Specifications]] and continues its running example,&lt;br /&gt;
&amp;lt;code&amp;gt;PeggedOrder&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== The execution model ==&lt;br /&gt;
&lt;br /&gt;
The entire machine runs on a single &amp;lt;code&amp;gt;beam.RoutineTaskQueue&amp;lt;/code&amp;gt;.&lt;br /&gt;
Every event such as market data, execution reports, timer expiries, the order's&lt;br /&gt;
own cancel request is delivered onto that queue and processed one task at a&lt;br /&gt;
time, in order of arrival.&lt;br /&gt;
&lt;br /&gt;
== The class ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import beam&lt;br /&gt;
import nexus&lt;br /&gt;
&lt;br /&gt;
class PeggedOrder:&lt;br /&gt;
  &amp;quot;&amp;quot;&amp;quot;Trades an order passively at a price pegged to the touch, honoring the&lt;br /&gt;
  order's limit price. The order's type is superseded: every submission is a&lt;br /&gt;
  limit order.&lt;br /&gt;
  &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  def __init__(self, clients, order_fields, peg_difference):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Constructs a PeggedOrder.&lt;br /&gt;
    @param clients The clients used to access Nexus services.&lt;br /&gt;
    @param order_fields The specification of the order to execute.&lt;br /&gt;
    @param peg_difference The difference applied to the pegged price.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    self._clients = clients&lt;br /&gt;
    self._order_fields = nexus.OrderFields(order_fields)&lt;br /&gt;
    self._peg_difference = peg_difference&lt;br /&gt;
    self._state = None&lt;br /&gt;
    self._failure = None&lt;br /&gt;
    self._orders = beam.QueueWriterPublisher()&lt;br /&gt;
    self._tasks = beam.RoutineTaskQueue()&lt;br /&gt;
    self._tasks.push(self._s0)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Conventions, in order of appearance:&lt;br /&gt;
&lt;br /&gt;
* Import only what the file uses.&lt;br /&gt;
* The class docstring states the goal, never the mechanics or implementation details; the constructor docstring documents each parameter with &amp;lt;code&amp;gt;@param&amp;lt;/code&amp;gt; lines copied verbatim from the specification's Parameters section. Methods common to all orders (&amp;lt;code&amp;gt;cancel&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;wait&amp;lt;/code&amp;gt;) are not documented.&lt;br /&gt;
* The constructor is responsible for starting the state machine in state S0 by pushing &amp;lt;code&amp;gt;self._s0&amp;lt;/code&amp;gt; onto the task queue.&lt;br /&gt;
* Every field and internal method takes a &amp;lt;code&amp;gt;_&amp;lt;/code&amp;gt; prefix. Mutable parameters are stored as copies (&amp;lt;code&amp;gt;nexus.OrderFields(order_fields)&amp;lt;/code&amp;gt;) so the caller can't mutate a running machine.&lt;br /&gt;
* State machines for order types should have an &amp;lt;code&amp;gt;orders&amp;lt;/code&amp;gt; publisher created in the constructor that is used to publish any submitted orders so they can be traced back to the state machine.&lt;br /&gt;
&lt;br /&gt;
Constructor parameters are exposed as read-only properties, returning copies&lt;br /&gt;
of mutable types to avoid inadvertant mutation:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  @property&lt;br /&gt;
  def order_fields(self):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Returns a copy of the specification of the order being executed.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    return nexus.OrderFields(self._order_fields)&lt;br /&gt;
&lt;br /&gt;
  @property&lt;br /&gt;
  def peg_difference(self):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Returns the difference applied to the pegged price.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    return self._peg_difference&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cancel&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;wait&amp;lt;/code&amp;gt; complete the remainder of the public API:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def cancel(self):&lt;br /&gt;
    try:&lt;br /&gt;
      self._tasks.push(self._on_cancel)&lt;br /&gt;
    except beam.PipeBrokenException:&lt;br /&gt;
      pass&lt;br /&gt;
&lt;br /&gt;
  def wait(self):&lt;br /&gt;
    self._tasks.wait()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cancel&amp;lt;/code&amp;gt; delivers the global cancel event through the same serialized&lt;br /&gt;
task queue as everything else, so it can never race with another event.&lt;br /&gt;
&lt;br /&gt;
== Transcribing states ==&lt;br /&gt;
&lt;br /&gt;
State &amp;lt;code&amp;gt;Sn&amp;lt;/code&amp;gt; becomes method &amp;lt;code&amp;gt;_sn&amp;lt;/code&amp;gt;. Its first line&lt;br /&gt;
records the state and its remaining lines are the specification's action,&lt;br /&gt;
followed by the state's conditions in label order. Each condition is an&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;elif&amp;lt;/code&amp;gt; returning the call to its target state,&lt;br /&gt;
marked with a comment naming the condition — the only comments in the file&lt;br /&gt;
are these specification markers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def _s1(self):&lt;br /&gt;
    self._state = 1&lt;br /&gt;
    if self._filled_quantity == self._order_fields.quantity:&lt;br /&gt;
&lt;br /&gt;
      # C0&lt;br /&gt;
      return self._s6()&lt;br /&gt;
&lt;br /&gt;
    # epsilon&lt;br /&gt;
    return self._s2()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The bare &amp;lt;code&amp;gt;return self._s2()&amp;lt;/code&amp;gt; is S1's &amp;amp;#949; transition: after&lt;br /&gt;
the conditions fail, the transition fires unconditionally. A state's action&lt;br /&gt;
transcribes nearly verbatim because the specification is already written in&lt;br /&gt;
real API syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def _s2(self):&lt;br /&gt;
    self._state = 2&lt;br /&gt;
    self._submission_price = self._peg_price&lt;br /&gt;
    fields = nexus.OrderFields(self._order_fields)&lt;br /&gt;
    fields.type = nexus.OrderType.LIMIT&lt;br /&gt;
    fields.price = self._submission_price&lt;br /&gt;
    fields.quantity = self._order_fields.quantity - self._filled_quantity&lt;br /&gt;
    self._order = self._clients.order_execution_client.submit(fields)&lt;br /&gt;
    self._order.publisher.monitor(&lt;br /&gt;
      self._tasks.get_slot(self._on_execution_report))&lt;br /&gt;
    self._orders.push(self._order)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Two lines here are implicit from the state machine specification, the&lt;br /&gt;
&amp;lt;code&amp;gt;monitor&amp;lt;/code&amp;gt; call is the method that publishes the order's events&lt;br /&gt;
onto the task queue, and &amp;lt;code&amp;gt;self._orders.push&amp;lt;/code&amp;gt; is how the PeggedOrder&lt;br /&gt;
publishes orders to external observers.&lt;br /&gt;
&lt;br /&gt;
Terminal states close everything the machine owns as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def _s3(self):&lt;br /&gt;
    self._state = 3&lt;br /&gt;
    self._orders.close(self._failure)&lt;br /&gt;
    self._tasks.close()&lt;br /&gt;
&lt;br /&gt;
  def _s6(self):&lt;br /&gt;
    self._state = 6&lt;br /&gt;
    self._orders.close()&lt;br /&gt;
    self._tasks.close()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The red terminal state closes the orders publisher '''with the failure''', so&lt;br /&gt;
observers receive the original exception and the blue terminal closes it&lt;br /&gt;
normally. Closing the task queue is what unblocks &amp;lt;code&amp;gt;wait&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Transcribing events ==&lt;br /&gt;
&lt;br /&gt;
Each event source gets a handler wired through&lt;br /&gt;
&amp;lt;code&amp;gt;self._tasks.get_slot(...)&amp;lt;/code&amp;gt;. The handler's top transcribes the&lt;br /&gt;
event bodies that always execute — the base event's body first — and the&lt;br /&gt;
rest dispatches on &amp;lt;code&amp;gt;self._state&amp;lt;/code&amp;gt;, checking each refinement's&lt;br /&gt;
guard in label order, with a comment marking each transition's event:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def _on_execution_report(self, report):&lt;br /&gt;
&lt;br /&gt;
    # E1&lt;br /&gt;
    self._filled_quantity += report.last_quantity&lt;br /&gt;
    if self._state == 2:&lt;br /&gt;
      if report.status == nexus.OrderStatus.REJECTED:&lt;br /&gt;
&lt;br /&gt;
        # E2&lt;br /&gt;
        self._failure = RuntimeError(report.text)&lt;br /&gt;
        return self._s3()&lt;br /&gt;
      elif report.status == nexus.OrderStatus.NEW:&lt;br /&gt;
&lt;br /&gt;
        # E3&lt;br /&gt;
        return self._s4()&lt;br /&gt;
    elif self._state == 4:&lt;br /&gt;
      if nexus.is_terminal(report.status):&lt;br /&gt;
&lt;br /&gt;
        # E4&lt;br /&gt;
        return self._s1()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The structure mirrors the specification exactly: E1's accounting runs on every&lt;br /&gt;
report because E1 happened, regardless of state; the state dispatch then&lt;br /&gt;
performs at most one transition, and checking REJECTED before&lt;br /&gt;
&amp;lt;code&amp;gt;is_terminal&amp;lt;/code&amp;gt; preserves the label order that resolves their&lt;br /&gt;
overlap. States with no edge for an event simply have no branch — the body&lt;br /&gt;
still ran, the machine stays put.&lt;br /&gt;
&lt;br /&gt;
A derived variable computed in an event body is recomputed in the handler,&lt;br /&gt;
before the dispatch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def _on_bbo_quote(self, quote):&lt;br /&gt;
&lt;br /&gt;
    # E0&lt;br /&gt;
    self._bbo = quote&lt;br /&gt;
    self._peg_price = nexus.pick(self._order_fields.side,&lt;br /&gt;
      self._bbo.ask.price, self._bbo.bid.price) - \&lt;br /&gt;
      nexus.direction(self._order_fields.side) * self._peg_difference&lt;br /&gt;
    if self._order_fields.price != nexus.Money.ZERO:&lt;br /&gt;
      self._peg_price = nexus.pick(self._order_fields.side,&lt;br /&gt;
        max(self._peg_price, self._order_fields.price),&lt;br /&gt;
        min(self._peg_price, self._order_fields.price))&lt;br /&gt;
    if self._state == 0:&lt;br /&gt;
&lt;br /&gt;
      # E0&lt;br /&gt;
      return self._s1()&lt;br /&gt;
    elif self._state == 4:&lt;br /&gt;
&lt;br /&gt;
      # E0&lt;br /&gt;
      return self._s4()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The global cancel event's handler is implemented similarly:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def _on_cancel(self):&lt;br /&gt;
    if self._state == 0:&lt;br /&gt;
&lt;br /&gt;
      # E5&lt;br /&gt;
      return self._s6()&lt;br /&gt;
    elif self._state == 2:&lt;br /&gt;
&lt;br /&gt;
      # E5&lt;br /&gt;
      return self._s7()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Kamal</name></author>
		
	</entry>
</feed>