strategy

Manage entries, exits, and track position metrics for backtesting strategies. The strategy namespace provides order creation, cancellation, and real-time P&L tracking. Use with @script.strategy() decorator to enable position management.

Quick Example

from pynecore.lib import (
    close, high, low, strategy, ta, bar_index, script
)
from pynecore.types import Persistent

@script.strategy(title="Simple Strategy", initial_capital=10000)
def main():
    sma20: Persistent[float] = ta.sma(close, 20)
    
    if bar_index == 20:
        strategy.entry("long", strategy.long, qty=1)
    
    if ta.crossunder(close, sma20):
        strategy.close("long", comment="Exit on cross below")
    
    # Check performance
    pnl: float = strategy.netprofit
    position: float = strategy.position_size

Functions

strategy.entry()

Create a new order to open or add to a position. Modifies existing unfilled orders with the same id.

ParameterTypeDescription
idstrOrder identifier
directionintTrade direction: strategy.long or strategy.short
qtyfloat | NoneQuantity in units (optional, uses strategy default if None)
limitfloat | NoneLimit price for entry (optional)
stopfloat | NoneStop price for entry (optional)
oca_namestr | NoneOne-Cancels-All group identifier (optional)
oca_typeintOCA behavior type (optional)
commentstr | NoneOrder comment (optional)
alert_messagestr | NoneAlert message text (optional)
disable_alertboolSuppress alerts if True (optional)

Returns: None

strategy.entry("long_1", strategy.long, qty=2.5)
strategy.entry("entry_limit", strategy.long, qty=1, limit=100.5)

strategy.exit()

Create price-based exit orders (take-profit, stop-loss, or trailing stop). Modifies existing unfilled orders with the same id.

ParameterTypeDescription
idstrExit order identifier
from_entrystr | NoneEntry id to exit (optional, exits from any entry if None)
qtyfloat | NoneExit quantity (optional)
qty_percentfloat | NoneExit as % of position (optional)
profitfloat | NoneTake-profit distance in ticks (optional)
limitfloat | NoneLimit price for take-profit (optional)
lossfloat | NoneStop-loss distance in ticks (optional)
stopfloat | NoneStop price for stop-loss (optional)
trail_pricefloat | NoneTrailing-stop activation price (optional)
trail_pointsfloat | NoneTrailing-stop activation distance in ticks (optional)
trail_offsetfloat | NoneTrailing-stop offset in ticks (optional)
oca_namestr | NoneOCA group identifier (optional)
commentstr | NoneOrder comment (optional)
comment_profitstr | NoneTP comment (optional)
comment_lossstr | NoneSL comment (optional)
comment_trailingstr | NoneTrailing stop comment (optional)
alert_messagestr | NoneAlert text (optional)
alert_profitstr | NoneTP alert (optional)
alert_lossstr | NoneSL alert (optional)
alert_trailingstr | NoneTrailing alert (optional)
disable_alertboolSuppress alerts if True (optional)

Returns: None

strategy.exit("tp_sl", qty_percent=100, profit=500, loss=200)
strategy.exit("trail", trail_points=50, comment="Trailing stop")

strategy.close()

Exit a position opened by entries with a specific id. Closes the position immediately at market price.

ParameterTypeDescription
idstrEntry id to close
commentstr | NoneOrder comment (optional)
qtyfloat | NonePartial close quantity (optional)
qty_percentfloat | NonePartial close as % of position (optional)
alert_messagestr | NoneAlert text (optional)
immediatelyboolClose at market immediately (optional)
disable_alertboolSuppress alerts if True (optional)

Returns: None

strategy.close("long_1", comment="Exit signal")
strategy.close("entry_a", qty_percent=50)

strategy.close_all()

Close the entire open position immediately at market price, regardless of entry ids.

ParameterTypeDescription
commentstr | NoneOrder comment (optional)
alert_messagestr | NoneAlert text (optional)
immediatelyboolClose immediately (optional)
disable_alertboolSuppress alerts if True (optional)

Returns: None

strategy.close_all(comment="Exit all positions")

strategy.order()

Create a new order to open, add to, or exit a position. Modifies existing unfilled orders with the same id.

ParameterTypeDescription
idstrOrder identifier
directionintTrade direction: strategy.long or strategy.short
qtyfloat | NoneQuantity in units (optional)
limitfloat | NoneLimit price (optional)
stopfloat | NoneStop price (optional)
oca_namestr | NoneOCA group identifier (optional)
oca_typeintOCA behavior type (optional)
commentstr | NoneOrder comment (optional)
alert_messagestr | NoneAlert text (optional)
disable_alertboolSuppress alerts if True (optional)

Returns: None

strategy.order("hedge", strategy.short, qty=1, limit=99.5)

strategy.cancel()

Cancel a pending or unfilled order by id. Cancels all orders sharing the same id.

ParameterTypeDescription
idstrOrder identifier to cancel

Returns: None

strategy.cancel("limit_order")

strategy.cancel_all()

Cancel all pending or unfilled orders regardless of id.

Returns: None

strategy.cancel_all()

disable_alert is accepted for Pine compatibility. PyneCore currently records alert messages on orders but does not dispatch order-fill alerts, so the parameter has no additional runtime effect.

strategy.default_entry_qty()

Quantity a default-sized strategy.entry() / strategy.order() would buy at a given fill price, derived from default_qty_type and default_qty_value.

ParameterTypeDescription
fill_pricefloatFill price to evaluate

Returns: float

The price is snapped onto the tick grid before the size is computed, and the size is then floored onto the lot grid. With strategy.fixed sizing the price is ignored entirely; with money-based sizing a price of na — or one that snaps to zero — gives 0. An open position is not considered, so a reversing order reports its own quantity, not the amount needed to flip the position.

qty = strategy.default_entry_qty(close)

Variables

NameTypeDescription
position_sizefloatCurrent position size (> 0 = long, < 0 = short, 0 = flat).
position_avg_pricefloatAverage entry price of current position. Returns NaN if flat.
position_entry_namestringEntry id of the position’s first open trade. Empty string if flat.
opentradesintCount of currently open (filled, not yet closed) trades. Pending orders are not counted.
openprofitfloatCurrent unrealized P&L for all open positions in currency units.
openprofit_percentfloatUnrealized P&L as % of the initial capital.
closedtradesintTotal count of closed trades for the entire trading range.
wintradesintCount of winning trades.
losstradesintCount of losing trades.
eventradesintCount of breakeven trades.
netprofitfloatTotal realized P&L for all closed trades in currency units.
netprofit_percentfloatRealized P&L as % of the initial capital.
grossprofitfloatTotal P&L from winning trades in currency units.
grossprofit_percentfloatGross profit as % of the initial capital.
grosslossfloatTotal P&L from losing trades in currency units.
grossloss_percentfloatGross loss as % of the initial capital. Open commission counts toward it, so a position that is still open already shows a loss percent.
avg_tradefloatAverage P&L of the closed trades in currency units.
avg_trade_percentfloatMean of the closed trades’ own profit percentages. Each trade’s percent divides by that trade’s entry cost — position value plus the fee paid to open it — so this is not netprofit_percent / closedtrades.
avg_winning_tradefloatAverage P&L of the winning trades in currency units.
avg_winning_trade_percentfloatMean of the winning trades’ own profit percentages.
avg_losing_tradefloatAverage loss per losing trade, as a POSITIVE amount — the same sign as grossloss, and it counts the open commission the same way.
avg_losing_trade_percentfloatMean of the losing trades’ own profit percentages. Negative, unlike the currency average above.
equityfloatCurrent equity = initial_capital + netprofit + openprofit.
max_drawdownfloatMaximum equity drawdown from peak in currency units.
max_drawdown_percentfloatMaximum drawdown as % of the equity peak it fell from. Tracked on its own, so it can be set on a different bar than max_drawdown.
max_runupfloatMaximum equity run-up from trough in currency units.
max_runup_percentfloatMaximum run-up as % of the equity top it rose to. Tracked on its own, like max_drawdown_percent.
max_contracts_held_allfloatLargest position size held, either direction.
max_contracts_held_longfloatLargest long position size held.
max_contracts_held_shortfloatLargest short position size held, as a positive number.
margin_liquidation_pricefloatPrice at which the margin call liquidates the position. NaN when no margin is set or the position is flat.
initial_capitalfloatInitial capital set in strategy properties.
account_currencystringAccount currency of the strategy.

Constants

NameTypeDescription
longintDirection constant for strategy.entry() and strategy.order(). Creates a buy/long position.
shortintDirection constant for strategy.entry() and strategy.order(). Creates a sell/short position.
fixedQtyTypeQuantity type for strategy properties. Fixed number of units per entry.
cashQtyTypeQuantity type for strategy properties. Fixed currency amount per entry.
percent_of_equityQtyTypeQuantity type for strategy properties. Percentage of equity per entry.

Compatibility

Order sizing:

  • Only a positive, finite qty is placed. A quantity that cannot be sized — na or infinite — is dropped like a non-positive one. This also covers a default-sized order whose size resolves to na, for example default_qty_value=na with strategy.percent_of_equity sizing. Pine Script rejects an na default_qty_value at compile time, so this only concerns hand-written Pyne code.