Documentation
¶
Overview ¶
Package types defines the core domain values shared across the order book and matching engine: orders, trades, and the small set of errors they raise.
Prices and quantities are exact decimals (shopspring/decimal) — never floats — so that money arithmetic is precise. This is the single most important correctness decision in the project; see docs/SPEC.md §6.1.
Index ¶
- Variables
- type IcebergOrder
- type OCOOrder
- type Order
- func (o *Order) AsPostOnly() *Order
- func (o *Order) Cancel() error
- func (o *Order) Fill(qty decimal.Decimal) error
- func (o *Order) Fresh() *Order
- func (o *Order) IsActive() bool
- func (o *Order) IsFilled() bool
- func (o *Order) NotionalValue() decimal.Decimal
- func (o *Order) RemainingValue() decimal.Decimal
- type OrderStatus
- type OrderType
- type PegReference
- type PeggedOrder
- type Side
- type StopOrder
- type TimeInForce
- type Trade
- type TrailingStop
Constants ¶
This section is empty.
Variables ¶
var ( ErrInvalidPrice = errors.New("invalid price: must be positive") ErrInvalidQuantity = errors.New("invalid quantity: must be positive") ErrInvalidSide = errors.New("invalid order side") ErrInvalidOrderType = errors.New("invalid order type") ErrInvalidTimeInForce = errors.New("invalid time in force") )
Validation errors raised when constructing orders.
var ( ErrFillExceedsRemaining = errors.New("fill quantity exceeds remaining quantity") ErrOrderNotFound = errors.New("order not found") ErrOrderNotActive = errors.New("order is not active") ErrOrderBookFull = errors.New("order book has reached maximum capacity") ErrMarketOrderNoLiquidity = errors.New("market order cannot be filled: no liquidity") ErrFOKCannotFill = errors.New("FOK order cannot be fully filled") ErrSelfTradeNotAllowed = errors.New("self-trade not allowed") ErrNilOrder = errors.New("order must not be nil") ErrInvalidStopPrice = errors.New("invalid stop price: must be positive") ErrPostOnlyWouldCross = errors.New("post-only order would cross the spread") ErrInvalidDisplayQuantity = errors.New("display quantity must be positive and <= total quantity") ErrInvalidPegReference = errors.New("invalid peg reference") ErrTradingHalted = errors.New("trading is halted") ErrPriceOutsideBand = errors.New("price is outside the allowed band") )
Lifecycle / matching errors.
Functions ¶
This section is empty.
Types ¶
type IcebergOrder ¶
type IcebergOrder struct {
Order *Order // the currently displayed slice (Quantity == a display chunk)
DisplayQty decimal.Decimal // size shown per slice
Hidden decimal.Decimal // quantity not yet displayed
}
IcebergOrder shows only a small slice of a large order to the book at a time. The visible slice (Order) rests like an ordinary limit; when it is fully consumed the order refills the next slice from its hidden reserve, until the total quantity is worked off. This is how large participants avoid signalling their full size (docs/SPEC.md §5.1).
func NewIcebergOrder ¶
func NewIcebergOrder(order *Order, displayQty decimal.Decimal) (*IcebergOrder, error)
NewIcebergOrder wraps order (whose Quantity is the TOTAL size) so that only displayQty is visible at a time. displayQty must be positive and no larger than the total.
func (*IcebergOrder) IsFullyFilled ¶
func (ib *IcebergOrder) IsFullyFilled() bool
IsFullyFilled reports whether both the hidden reserve and the visible slice are exhausted.
func (*IcebergOrder) Refill ¶
func (ib *IcebergOrder) Refill() bool
Refill loads the next slice into Order (resetting its fill state to the new chunk size) and returns true. It returns false when nothing is hidden.
func (*IcebergOrder) TotalRemaining ¶
func (ib *IcebergOrder) TotalRemaining() decimal.Decimal
TotalRemaining is the hidden reserve plus the unfilled part of the visible slice.
type OCOOrder ¶
OCOOrder links two orders so that completing one cancels the other. The canonical use is a bracket exit for an open position: a take-profit limit (Primary) paired with a stop-loss (Stop). Whichever fires first, the engine cancels its counterpart (docs/SPEC.md §5.1).
type Order ¶
type Order struct {
ID string `json:"id"`
UserID string `json:"user_id"`
Symbol string `json:"symbol"`
Side Side `json:"side"`
Type OrderType `json:"type"`
Price decimal.Decimal `json:"price"`
Quantity decimal.Decimal `json:"quantity"`
FilledQty decimal.Decimal `json:"filled_qty"`
RemainingQty decimal.Decimal `json:"remaining_qty"`
TimeInForce TimeInForce `json:"time_in_force"`
PostOnly bool `json:"post_only,omitempty"` // maker-only: reject if it would cross
Status OrderStatus `json:"status"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
SequenceNum uint64 `json:"sequence_num"`
}
Order is a single instruction to buy or sell a quantity of a symbol.
RemainingQty is the authoritative "how much is still live" figure the matching engine reads and mutates; FilledQty + RemainingQty always equals Quantity.
func NewOrder ¶
func NewOrder(userID, symbol string, side Side, orderType OrderType, price, quantity decimal.Decimal, tif TimeInForce) (*Order, error)
NewOrder constructs a validated order with a time-ordered UUIDv7 id.
Quantity must be positive. Limit orders require a positive price; market orders ignore price (it is forced to zero, since a market order takes whatever the book offers).
func (*Order) AsPostOnly ¶
AsPostOnly marks the order maker-only and returns it (for fluent construction). A post-only order is rejected if it would cross the spread instead of resting.
func (*Order) Cancel ¶
Cancel marks the order cancelled. Filled or already-cancelled orders cannot be cancelled.
func (*Order) Fill ¶
Fill applies a fill of qty to the order, advancing FilledQty/RemainingQty and Status. It returns an error if qty is non-positive or exceeds RemainingQty.
func (*Order) Fresh ¶
Fresh returns a copy of the order reset to its initial, unfilled state (FilledQty=0, RemainingQty=Quantity, Status=NEW, SequenceNum=0) while keeping its identity and parameters (ID, user, symbol, side, type, price, quantity, TIF). It exists for deterministic replay and simulation, where the same order must be re-submitted to a fresh engine without carrying prior fill state. The original order is not modified.
func (*Order) NotionalValue ¶
NotionalValue is Price × Quantity (zero for market orders, which have no price).
func (*Order) RemainingValue ¶
RemainingValue is Price × RemainingQty.
type OrderStatus ¶
type OrderStatus string
OrderStatus is the lifecycle state of an order.
const ( OrderStatusNew OrderStatus = "NEW" OrderStatusPartiallyFilled OrderStatus = "PARTIALLY_FILLED" OrderStatusFilled OrderStatus = "FILLED" OrderStatusCancelled OrderStatus = "CANCELLED" OrderStatusRejected OrderStatus = "REJECTED" OrderStatusPendingTrigger OrderStatus = "PENDING_TRIGGER" // resting stop, not yet fired )
type PegReference ¶
type PegReference string
PegReference is the market price a pegged order tracks.
const ( PegToBid PegReference = "BID" // best bid PegToAsk PegReference = "ASK" // best ask PegToMid PegReference = "MID" // mid price )
type PeggedOrder ¶
type PeggedOrder struct {
Order *Order
Ref PegReference
Offset decimal.Decimal
}
PeggedOrder is a limit order whose price is derived from a market reference plus a signed offset at the moment it is submitted (price = reference + Offset). This is a static peg — it resolves once on entry; continuously re-pegging as the book moves is a future extension (docs/SPEC.md §5.1).
func NewPeggedOrder ¶
func NewPeggedOrder(order *Order, ref PegReference, offset decimal.Decimal) (*PeggedOrder, error)
NewPeggedOrder wraps a limit order with a peg reference and offset.
type StopOrder ¶
type StopOrder struct {
Order *Order
StopPrice decimal.Decimal
// contains filtered or unexported fields
}
StopOrder is a trigger wrapper around an ordinary order. While resting it sits off-book; when the market price reaches StopPrice the underlying Order (a market order for a stop, or a limit order for a stop-limit) is released to the matching engine.
Direction follows the underlying side: a BUY stop triggers when the market rises to the stop (price ≥ StopPrice); a SELL stop triggers when the market falls to it (price ≤ StopPrice). A sell stop below the market is the classic stop-loss for a long position.
func NewStopOrder ¶
NewStopOrder wraps order with a positive stop price.
func (*StopOrder) IsTriggered ¶
IsTriggered reports whether the stop has fired.
func (*StopOrder) ShouldTrigger ¶
ShouldTrigger reports whether marketPrice has reached the stop (and it has not already fired).
type TimeInForce ¶
type TimeInForce string
TimeInForce controls how long an order remains active.
const ( // TIFGoodTillCancel rests until explicitly cancelled. TIFGoodTillCancel TimeInForce = "GTC" // TIFImmediateOrCancel fills what it can immediately, cancels the rest. TIFImmediateOrCancel TimeInForce = "IOC" // TIFFillOrKill fills the entire order immediately or cancels all of it. TIFFillOrKill TimeInForce = "FOK" )
type Trade ¶
type Trade struct {
ID string `json:"id"`
Symbol string `json:"symbol"`
Price decimal.Decimal `json:"price"`
Quantity decimal.Decimal `json:"quantity"`
BuyOrderID string `json:"buy_order_id"`
SellOrderID string `json:"sell_order_id"`
BuyerUserID string `json:"buyer_user_id"`
SellerUserID string `json:"seller_user_id"`
MakerOrderID string `json:"maker_order_id"`
TakerOrderID string `json:"taker_order_id"`
TakerSide Side `json:"taker_side"`
CreatedAt time.Time `json:"created_at"`
SequenceNum uint64 `json:"sequence_num"`
}
Trade is a single execution between a resting maker order and an incoming taker order. It always prints at the maker's (resting) price.
func NewTrade ¶
func NewTrade(symbol string, price, quantity decimal.Decimal, buyOrder, sellOrder *Order, takerSide Side) *Trade
NewTrade builds a trade from the matched buy/sell orders. takerSide identifies which side crossed the spread, from which maker/taker order ids are derived.
func (*Trade) IsSelfTrade ¶
IsSelfTrade reports whether both sides belong to the same user.
func (*Trade) NotionalValue ¶
NotionalValue is Price × Quantity of the trade.
type TrailingStop ¶
type TrailingStop struct {
Order *Order
Trail decimal.Decimal
// contains filtered or unexported fields
}
TrailingStop is a stop whose trigger price follows the market by a fixed Trail distance, ratcheting in the favourable direction and never retreating. A SELL trailing stop (protecting a long) trails Trail below the highest price seen and fires when price falls to it; a BUY trailing stop (protecting a short) trails Trail above the lowest price seen (docs/SPEC.md §5.1).
func NewTrailingStop ¶
func NewTrailingStop(order *Order, trail decimal.Decimal) (*TrailingStop, error)
NewTrailingStop wraps order with a positive trail distance.
func (*TrailingStop) IsTriggered ¶
func (ts *TrailingStop) IsTriggered() bool
IsTriggered reports whether the trailing stop has fired.
func (*TrailingStop) Observe ¶
func (ts *TrailingStop) Observe(marketPrice decimal.Decimal)
Observe updates the trailing extreme and stop price from a new market price. The extreme only moves favourably, so the stop only ratchets.
func (*TrailingStop) ShouldTrigger ¶
func (ts *TrailingStop) ShouldTrigger(marketPrice decimal.Decimal) bool
ShouldTrigger reports whether marketPrice has reached the trailed stop.
func (*TrailingStop) StopPrice ¶
func (ts *TrailingStop) StopPrice() decimal.Decimal
StopPrice returns the current trailed trigger price.
func (*TrailingStop) Trigger ¶
func (ts *TrailingStop) Trigger()
Trigger fires the trailing stop, releasing its underlying order.