Bourse.OptionSaga (bourse v0.1.0)

Copy Markdown View Source

Observable, caller-held execution saga for approved option plans.

new/2 converts a fresh %Bourse.OptionProposal.Result{status: :approved} into a journal with stable plan, leg, and client-order identifiers. step/3 is pure: it returns at most one command and the journal state that must be retained before that command is executed. execute/3 performs that single effect. resume/4 is pure and records the exact observed outcome.

A submission with an ambiguous outcome becomes :unknown. The next command is reconciliation, never another submission. Definite failures stop later legs and switch to cancellation of reversible acknowledged remainders. Filled exposure is reported as residual risk requiring caller action; it is never described as rolled back.

Summary

Functions

Executes exactly one command against caller-supplied exchange configurations.

Creates a journal from a fresh approved preflight result.

Records one command outcome in the caller-held journal.

Emits the next command and the journal state that precedes its execution.

Types

command()

@type command() :: %{
  :id => String.t(),
  :action => command_action(),
  :plan_id => String.t(),
  :approval_id => String.t(),
  :leg_id => term(),
  :execution_id => String.t(),
  :client_order_id => String.t(),
  :venue => String.t(),
  :account => term(),
  :symbol => String.t(),
  :type => String.t(),
  :side => String.t(),
  :amount => number(),
  optional(:price) => number() | nil,
  optional(:order_id) => String.t() | nil
}

command_action()

@type command_action() :: :submit | :reconcile | :cancel

outcome()

@type outcome() :: Bourse.OptionSaga.Executor.outcome()

Functions

execute(command, exchanges, opts \\ [])

Executes exactly one command against caller-supplied exchange configurations.

new(approval, opts \\ [])

Creates a journal from a fresh approved preflight result.

Options:

  • :now_ms — current time override
  • :max_approval_age_ms — maximum age before a new submission is refused

resume(journal, command, outcome, opts \\ [])

Records one command outcome in the caller-held journal.

Replaying the same command outcome is idempotent. An outcome for another plan, approval, or leg is rejected.

step(journal, approval, opts \\ [])

Emits the next command and the journal state that precedes its execution.

New submissions re-check both approval identity and freshness before a command is returned. Reconciliation and compensation remain available after approval expiry because they reduce uncertainty or risk rather than add a new planned exposure.