An open or closed paper position.
A Position is created when a PaperEx.Order produces a :filled
PaperEx.Execution. It carries the entry data plus, when closed,
the exit data and realized P&L. The struct is plain data; the engine
that opens, closes, and resolves positions lives in PaperEx.Engine.
Lifecycle
:open— the position holds shares;:exit_price,:pnl, and:closed_atare allnil.:closed— the position has been fully exited;:exit_price,:pnl, and:closed_atare populated.
Partial closes are modeled with a parent/child split. When
PaperEx.Engine partially sells (or short-covers) an open position,
it books a :closed child Position for the closed shares —
carrying that slice's realized :pnl, :exit_price, and
:closed_at — onto the portfolio's :history, while the parent
stays :open with reduced :shares at its original
:entry_price basis. A full close simply transitions the position
itself to :closed.
Fields
:id— caller-assignable identifier.:order_id— thePaperEx.Orderthat opened this position.:execution_id— the:filledPaperEx.Executionrecord that created this position.:market_id(required) — opaque exchange-specific market id.:side(required) —:buyor:sell.:entry_price(required) — execution price per share.:shares(required) — number of units held.:strategy— optional binary tag, copied from theOrder.:metadata— free-form map, copied from theOrderand possibly augmented by the engine.:status(required) —:openor:closed.:exit_price— populated on close.:pnl— realized profit or loss on close. Sign convention is P&L-positive-is-profit; the engine computes it inPaperEx.Engine.:opened_at—DateTime.t()(defaults toDateTime.utc_now/0).:closed_at—DateTime.t(), populated on close.
Summary
Types
@type id() :: term() | nil
@type market_id() :: term()
@type side() :: :buy | :sell
@type status() :: :open | :closed
@type t() :: %PaperEx.Position{ closed_at: DateTime.t() | nil, entry_price: number(), execution_id: term() | nil, exit_price: number() | nil, id: id(), market_id: market_id(), metadata: map(), opened_at: DateTime.t(), order_id: term() | nil, pnl: number() | nil, shares: number(), side: side(), status: status(), strategy: String.t() | nil }
Functions
Builds a Position from a map or keyword list.
Required: :market_id, :side, :entry_price, :shares.
:status defaults to :open. When :status is :closed,
:exit_price, :pnl, and :closed_at must all be set.
@spec statuses() :: [status()]
Returns the list of valid :status atoms.