pybroker.portfolio module
Contains portfolio related functionality, such as portfolio metrics and placing orders.
- class Entry(id: int, date: ~numpy.datetime64, symbol: str, shares: ~decimal.Decimal, price: ~decimal.Decimal, type: ~typing.Literal['long', 'short'], bars: int = 0, sym_bars: int = 0, stops: list[~pybroker.portfolio.Stop] = <factory>, mae: ~decimal.Decimal = <factory>, mfe: ~decimal.Decimal = <factory>)[source]
Bases:
objectContains information about an entry into a
Position.- date
Date of the entry.
- Type:
Number of shares.
- Type:
- price
Share price of the entry.
- Type:
- bars
Current number of bars since entry, counted on the portfolio’s clock: every bar of the backtest, whether or not
symboltraded on it. FeedsTrade.barsandpnl_per_bar, which measure elapsed holding time.- Type:
- sym_bars
Current number of
symbol’s own bars since entry. Advances only on datessymbolhas a bar, so it matches whatpybroker.context.ExecContext.barsreports. This is whatpybroker.common.StopType.BARstops count against: when calendars are ragged,barswould expire ahold_barsstop after fewer of the symbol’s own bars than the caller asked for.- Type:
- stops
Stops set on the entry.
- Type:
- mae
Maximum adverse excursion (MAE).
- Type:
- mfe
Maximum favorable excursion (MFE).
- Type:
- class Order(id: int, type: Literal['buy', 'sell'], symbol: str, date: datetime64, created: datetime64 | None, order_type: Literal['market', 'limit', 'stop_bar', 'stop_loss', 'stop_profit', 'stop_trailing'], intent: Literal['buy_to_open', 'buy_to_close', 'sell_to_open', 'sell_to_close'], shares: Decimal, limit_price: Decimal | None, market_price: Decimal, fill_price: Decimal, fees: Decimal)[source]
Bases:
NamedTupleHolds information about a filled order.
- type
Type of order, either
buyorsell.- Type:
Literal[‘buy’, ‘sell’]
- date
Date the order was filled.
- Type:
- created
Date the order signal was created, or
Nonefor stop-triggered orders.- Type:
numpy.datetime64 | None
- order_type
How the order originated, either
market,limit,stop_bar,stop_loss,stop_profit, orstop_trailing.- Type:
Literal[‘market’, ‘limit’, ‘stop_bar’, ‘stop_loss’, ‘stop_profit’, ‘stop_trailing’]
- intent
Position intent, either
buy_to_open,buy_to_close,sell_to_open, orsell_to_close.- Type:
Literal[‘buy_to_open’, ‘buy_to_close’, ‘sell_to_open’, ‘sell_to_close’]
Number of shares bought or sold.
- Type:
- limit_price
Limit price that was used for the order.
- Type:
decimal.Decimal | None
- market_price
Market price prevailing when the order was filled, before any fill-time slippage adjustment. Equal to
fill_pricewhen no slippage model is set.- Type:
- fill_price
Price that the order was filled at.
- Type:
- fees
Brokerage fees for order.
- Type:
- class Portfolio(cash: float, fee_mode: FeeMode | Callable[[FeeInfo], Decimal] | None = None, fee_amount: float | None = None, enable_fractional_shares: bool = False, position_mode: PositionMode = PositionMode.DEFAULT, max_long_positions: int | None = None, max_short_positions: int | None = None, record_stops: bool | None = False, leverage: float = 1.0, interest_rate: float = 0.0, bars_per_year: int | None = None, record_portfolio_bars: bool = False, record_position_bars: bool = False)[source]
Bases:
objectClass representing a portfolio of holdings. The portfolio contains information about open positions and balances, and is also used to place buy and sell orders.
- Parameters:
cash – Starting cash balance.
fee_mode – Brokerage fee mode.
fee_amount – Brokerage fee amount.
enable_fractional_shares – Whether to enable trading fractional shares.
position_mode – Position mode for
Portfolio.max_long_positions – Maximum number of long
Positions that can be held at a time. IfNone, then unlimited.max_short_positions – Maximum number of short
Positions that can be held at a time. IfNone, then unlimited.record_stops – Whether to record stop data per-bar.
- cash
Current cash balance.
- equity
Current amount of equity, defined as the net cash balance plus the market value of all open long positions plus the collateral posted for all open short positions. Short positions are held at cost, so their unrealized PnL is excluded.
- market_value
Current market value. The market value is defined as
equityadded together with the unrealized PnL of all open short positions.
- fees
Current brokerage fees.
- fee_amount
Brokerage fee amount.
Whether to enable trading fractional shares.
- orders
dequeof all filled orders, sorted in ascending chronological order.
- margin
Notional exposure of open short positions at mark.
- margin_loan
Borrowed funds used for leveraged long and short positions.
- pnl
Realized profit and loss (PnL).
- symbols
Ticker symbols of all currently open positions.
- position_bars
dequeof snapshots ofPositionstates on every bar, sorted in ascending chronological order.
- win_rate
Running win rate of trades.
- loss_rate
Running loss rate of trades.
- buy(date: datetime64, symbol: str, shares: Decimal, fill_price: Decimal, limit_price: Decimal | None = None, stops: Iterable[Stop] | None = None, created: datetime64 | None = None, order_type: OrderType = OrderType.MARKET, market_price: Decimal | None = None) Order | None[source]
Places a buy order.
- Parameters:
date – Date when the
Orderis placed.symbol – Ticker symbol to buy.
shares – Number of shares to buy.
fill_price – If filled, the price used to fill the
Order.limit_price – Limit price of the
Order.stops –
Stops to set on theEntrycreated from theOrder, if filled.created – Date the order signal was created.
order_type – How the order originated.
market_price – Market price at fill time, before fill-time slippage. Defaults to
fill_price.
- Returns:
Orderif the order was filled, otherwiseNone.
- capture_bar(date: datetime64, col_scope: ColumnScope, sym_end_index: Mapping[str, int], price_scope: PriceScope | None = None)[source]
Captures portfolio state of the current bar.
- check_stops(date: datetime64, price_scope: PriceScope, col_scope: ColumnScope | None = None, sym_end_index: Mapping[str, int] | None = None, ind_scope: IndicatorScope | None = None, slippage_model: SlippageModel | None = None)[source]
Checks whether stops are triggered.
Price stops on one entry are evaluated in ascending
Stop.idorder and the first one to trigger exits the entry. Ids are assigned whenpybroker.context.ExecContext.to_result()builds the stops, in a fixed order – loss, then profit, then trailing – not in the order the attributes were assigned on the context, so precedence is deterministic but not caller-controlled.pybroker.common.StopType.BARstops are evaluated after the price stops, whatever their id, because a bar-count exit and a price exit landing on the same bar have no true ordering: the bar’s price path decides, and it is not modeled here.When
slippage_modelis set, triggered stops fill at the adjusted price. Slippage never affects whether a stop triggers, and share adjustments are ignored because a stop exits its entry in full.
- exit_position(date: datetime64, symbol: str, buy_fill_price: Decimal, sell_fill_price: Decimal, col_scope: ColumnScope | None = None, ind_scope: IndicatorScope | None = None, sym_end_index: Mapping[str, int] | None = None, slippage_model: SlippageModel | None = None)[source]
Exits any long and short positions for
symbolatbuy_fill_priceandsell_fill_price.When
slippage_modelis set, both fills are adjusted by it. Share adjustments are ignored because the positions are exited in full. The unadjusted prices are recorded asmarket_priceon the resultingOrders.
- incr_bars(date: datetime64 | None = None, price_scope: PriceScope | None = None)[source]
Increments the number of bars held by every trade entry.
Entry.barsadvances on every bar of the backtest. Whendateandprice_scopeare given,Entry.sym_barsadvances only on dates the entry’s symbol has a bar of its own, which is whatpybroker.common.StopType.BARstops count against. Without them both counters advance together, matching a calendar where every symbol trades on every bar.
- remove_stops(val: str | Position | Entry, stop_type: StopType | None = None)[source]
Removes
Stops.- Parameters:
val – Ticker symbol,
Position, orEntryfor which to cancel stops.stop_type –
pybroker.common.StopType.
- sell(date: datetime64, symbol: str, shares: Decimal, fill_price: Decimal, limit_price: Decimal | None = None, stops: Iterable[Stop] | None = None, created: datetime64 | None = None, order_type: OrderType = OrderType.MARKET, market_price: Decimal | None = None) Order | None[source]
Places a sell order.
- Parameters:
date – Date when the
Orderis placed.symbol – Ticker symbol to sell.
shares – Number of shares to sell.
fill_price – If filled, the price used to fill the
Order.limit_price – Limit price of the
Order.stops –
Stops to set on theEntrycreated from theOrder, if filled.created – Date the order signal was created.
order_type – How the order originated.
market_price – Market price at fill time, before fill-time slippage. Defaults to
fill_price.
- Returns:
Orderif the order was filled, otherwiseNone.
- class PortfolioBar(date: datetime64, cash: Decimal, equity: Decimal, notional: Decimal, margin: Decimal, margin_loan: Decimal, net_cash_balance: Decimal, market_value: Decimal, pnl: Decimal, unrealized_pnl: Decimal, fees: Decimal)[source]
Bases:
NamedTupleSnapshot of
Portfoliostate, captured per bar.- date
Date of bar.
- Type:
- equity
Amount of equity in
Portfolio. Open short positions are held at cost, so their unrealized PnL is excluded.- Type:
- notional
Notional exposure of all open positions at mark: the market value of open long positions plus the
marginof open short positions.- Type:
- margin
Notional exposure of open short positions at mark.
- Type:
- margin_loan
Borrowed funds used for leveraged long and short positions.
- Type:
- net_cash_balance
cash - margin_loan.- Type:
- market_value
Market value of
Portfolio, equal toequityplus the unrealized PnL of all open short positions.- Type:
- unrealized_pnl
Unrealized profit and loss (PnL) of
Portfolio, equal tomarket_value - equity.- Type:
- fees
Brokerage fees.
- Type:
- class Position(symbol: str, shares: ~decimal.Decimal, type: ~typing.Literal['long', 'short'], close: ~decimal.Decimal = <factory>, equity: ~decimal.Decimal = <factory>, market_value: ~decimal.Decimal = <factory>, margin: ~decimal.Decimal = <factory>, pnl: ~decimal.Decimal = <factory>, entries: ~collections.deque[~pybroker.portfolio.Entry] = <factory>, bars: int = 0, entry_notional: ~decimal.Decimal = <factory>, unmarked_shares: ~decimal.Decimal = <factory>, unmarked_notional: ~decimal.Decimal = <factory>)[source]
Bases:
objectContains information about an open position in
symbol.Number of shares.
- Type:
- type
Type of position, either
longorshort.- Type:
Literal[‘long’, ‘short’]
- close
Last close price of
symbol.- Type:
- equity
Equity in the position.
- Type:
- market_value
Market value of position.
- Type:
- margin
Amount of margin in position.
- Type:
- pnl
Unrealized profit and loss (PnL).
- Type:
- entry_notional
Total cost basis of the position’s open entries.
- Type:
Shares acquired since the last mark. Valuing these at
closewould price them at a mark taken before they were bought, so they are held at cost until the next mark.- Type:
- unmarked_notional
Cost of
unmarked_shares, at fill price.- Type:
- class PositionBar(symbol: str, date: datetime64, long_shares: Decimal, short_shares: Decimal, close: Decimal, equity: Decimal, market_value: Decimal, margin: Decimal, unrealized_pnl: Decimal)[source]
Bases:
NamedTupleSnapshot of an open
Position‘s state, captured per bar.- date
Date of bar.
- Type:
Number of shares long in
Position.- Type:
Number of shares short in
Position.- Type:
- close
Last close price of
symbol.- Type:
- class Stop(id: int, symbol: str, stop_type: StopType, pos_type: Literal['long', 'short'], percent: Decimal | None, points: Decimal | None, bars: int | None, fill_price: int | float | floating | Decimal | PriceType | Callable[[str, BarData], int | float | Decimal] | None, limit_price: Decimal | None, exit_price: PriceType | None)[source]
Bases:
NamedTupleContains information about a stop set on
Entry.- stop_type
-
- Type:
- percent
Percent from entry price.
- Type:
decimal.Decimal | None
- points
Cash amount from entry price.
- Type:
decimal.Decimal | None
- fill_price
Price that the stop will be filled at.
- Type:
int | float | numpy.floating | decimal.Decimal | pybroker.common.PriceType | Callable[[str, pybroker.common.BarData], int | float | decimal.Decimal] | None
- limit_price
Limit price to use for the stop.
- Type:
decimal.Decimal | None
- exit_price
Exit
pybroker.common.PriceTypeto use for the stop exit. If set, the stop is checked against theexit_priceand exits at theexit_pricewhen triggered.- Type:
pybroker.common.PriceType | None
- class StopRecord(date: datetime64, symbol: str, stop_id: int, stop_type: str, pos_type: Literal['long', 'short'], curr_value: Decimal | None, curr_bars: int | None, percent: Decimal | None, points: Decimal | None, bars: int | None, fill_price: Decimal | None, limit_price: Decimal | None, exit_price: PriceType | None)[source]
Bases:
NamedTupleRecords per-bar data about a stop.
- date
Date of the bar.
- Type:
- curr_value
Current value of the stop.
- Type:
decimal.Decimal | None
- percent
Percent from entry price.
- Type:
decimal.Decimal | None
- points
Cash amount from entry price.
- Type:
decimal.Decimal | None
- fill_price
Price that the stop will be filled at.
- Type:
decimal.Decimal | None
- limit_price
Limit price to use for the stop.
- Type:
decimal.Decimal | None
- exit_price
Exit
pybroker.common.PriceTypeto use for the stop exit. If set, the stop is checked against theexit_priceand exits at theexit_pricewhen triggered.- Type:
pybroker.common.PriceType | None
- class Trade(id: int, type: Literal['long', 'short'], symbol: str, entry_date: datetime64, exit_date: datetime64, entry: Decimal, exit: Decimal, shares: Decimal, pnl: Decimal, return_pct: Decimal, agg_pnl: Decimal, bars: int, pnl_per_bar: Decimal, stop: Literal['bar', 'loss', 'profit', 'trailing'] | None, mae: Decimal, mfe: Decimal)[source]
Bases:
NamedTupleHolds information about a completed trade (entry and exit).
- type
Type of trade, either
longorshort.- Type:
Literal[‘long’, ‘short’]
- entry_date
Entry date.
- Type:
- exit_date
Exit date.
- Type:
- entry
Entry price.
- Type:
- exit
Exit price.
- Type:
Number of shares.
- Type:
- pnl
Profit and loss (PnL).
- Type:
- return_pct
Return measured in percentage.
- Type:
- agg_pnl
Aggregate profit and loss (PnL) of the strategy after the trade.
- Type:
- pnl_per_bar
Profit and loss (PnL) per bar held.
- Type:
- stop
Type of stop that was triggered, if any.
- Type:
Literal[‘bar’, ‘loss’, ‘profit’, ‘trailing’] | None
- mae
Maximum adverse excursion (MAE).
- Type:
- mfe
Maximum favorable excursion (MFE).
- Type: