investfly.models.portfolio

Portfolio and trading models

class Broker(builtins.str, enum.Enum):

Broker Type Enum

TRADIER = TRADIER
INVESTFLY = INVESTFLY
TASTYTRADE = TASTYTRADE
ALPACA = ALPACA
BACKTEST = BACKTEST
OANDA = OANDA
COINBASE = COINBASE
class PositionType(builtins.str, enum.Enum):

PositionType Enum

LONG = LONG
SHORT = SHORT
CLOSE = CLOSE
class TradeType(builtins.str, enum.Enum):

Trade Type Enum

BUY = BUY
SELL = SELL
SHORT = SHORT
COVER = COVER
class OrderType(builtins.str, enum.Enum):

Order Type Enum

MARKET_ORDER = <OrderType.MARKET_ORDER: 'MARKET_ORDER'>
LIMIT_ORDER = <OrderType.LIMIT_ORDER: 'LIMIT_ORDER'>
STOP_ORDER = <OrderType.STOP_ORDER: 'STOP_ORDER'>
ONE_CANCEL_OTHER = <OrderType.ONE_CANCEL_OTHER: 'ONE_CANCEL_OTHER'>
CUSTOM_CONDITION = <OrderType.CUSTOM_CONDITION: 'CUSTOM_CONDITION'>
@dataclass
class TradeOrder:

A class that represents a Trade Order.

For futures, if security is a product-level Security rather than a specific Future contract, the engine automatically resolves it to the front-month contract.

TradeOrder( security: investfly.models.marketdata.Security, tradeType: TradeType, orderType: OrderType = <OrderType.MARKET_ORDER: 'MARKET_ORDER'>, quantity: float | None = None, maxAmount: float | None = None, limitPrice: float | None = None)
tradeType: TradeType
orderType: OrderType = <OrderType.MARKET_ORDER: 'MARKET_ORDER'>
quantity: float | None = None
maxAmount: float | None = None
limitPrice: float | None = None
def toDict(self) -> Dict[str, Any]:
def validate(self) -> None:

Validate that required fields are provided

@dataclass
class MultiLegOrder:

One atomic option-combo ticket plus optional option-structure metadata.

MultiLegOrder( orders: List[TradeOrder], orderGroupId: Optional[str] = None, orderGroupType: str = 'COMBO', atomic: bool = True, optionStrategyTemplate: Optional[str] = None, optionLegRoles: Optional[List[str]] = None)
orders: List[TradeOrder]
orderGroupId: Optional[str] = None
orderGroupType: str = 'COMBO'
atomic: bool = True
optionStrategyTemplate: Optional[str] = None
optionLegRoles: Optional[List[str]] = None
def toDict(self) -> Dict[str, Any]:
@dataclass
class OrderStatus:

Trade Order Status

OrderStatus(orderId: int, status: str, message: str | None = None)
orderId: int
status: str
message: str | None = None
@staticmethod
def fromDict( jsonDict: Dict[str, Any]) -> OrderStatus:
@dataclass
class PendingOrder(investfly.models.portfolio.TradeOrder):
PendingOrder( security: investfly.models.marketdata.Security, tradeType: TradeType, orderType: 'OrderType' = <OrderType.MARKET_ORDER: 'MARKET_ORDER'>, quantity: float | None = None, maxAmount: float | None = None, limitPrice: float | None = None, orderId: str | None = None, status: str | None = None, scheduledDate: datetime.datetime | None = None)
orderId: str | None = None
status: str | None = None
scheduledDate: datetime.datetime | None = None
@staticmethod
def fromDict(jsonDict: Dict[str, Any]) -> Any:
@dataclass
class OpenPosition:
OpenPosition( security: investfly.models.marketdata.Security, position: PositionType, avgPrice: float, quantity: float, purchaseDate: datetime.datetime, currentPrice: float | None = None, currentValue: float | None = None, profitLoss: float | None = None, percentChange: float | None = None)
position: PositionType
avgPrice: float
quantity: float
purchaseDate: datetime.datetime
currentPrice: float | None = None
currentValue: float | None = None
profitLoss: float | None = None
percentChange: float | None = None
@staticmethod
def fromDict( jsonDict: Dict[str, Any]) -> OpenPosition:
def toDict(self) -> Dict[str, Any]:
@dataclass
class ClosedPosition:
ClosedPosition( security: investfly.models.marketdata.Security, position: PositionType, openDate: datetime.datetime, closeDate: datetime.datetime, openPrice: float, closePrice: float, quantity: float, profitLoss: float | None = None, percentChange: float | None = None)
position: PositionType
openDate: datetime.datetime
closeDate: datetime.datetime
openPrice: float
closePrice: float
quantity: float
profitLoss: float | None = None
percentChange: float | None = None
@staticmethod
def fromDict( jsonDict: Dict[str, Any]) -> ClosedPosition:
def toDict(self) -> Dict[str, Any]:
@dataclass
class CompletedTrade:
CompletedTrade( security: investfly.models.marketdata.Security, date: datetime.datetime, price: float, quantity: float, tradeType: TradeType)
date: datetime.datetime
price: float
quantity: float
tradeType: TradeType
@staticmethod
def fromDict( jsonDict: Dict[str, Any]) -> CompletedTrade:
@dataclass
class Balances:
Balances( buyingPower: float, cashBalance: float, currentValue: float, initialAmount: float | None = None, marginRequirement: float | None = None, percentChange: float | None = None)
buyingPower: float
cashBalance: float
currentValue: float
initialAmount: float | None = None
marginRequirement: float | None = None
percentChange: float | None = None
@staticmethod
def fromDict(jsonDict: Dict[str, Any]) -> Balances:
class Portfolio:
Portfolio( portfolioId: str, broker: Broker, balances: Balances)
portfolioId
broker
balances: Balances
openPositions: List[OpenPosition]
pendingOrders: List[PendingOrder]
completedTrades: List[CompletedTrade]
def findPosition( self, security: investfly.models.marketdata.Security, positionType: PositionType) -> OpenPosition | None:
@dataclass
class PortfolioPerformance:
PortfolioPerformance( netReturn: float | None = None, annualizedReturn: float | None = None, profitFactor: float | None = None, totalTrades: int | None = None, winRatioPct: float | None = None, avgProfitPerTradePct: float | None = None, avgLossPerTradePct: float | None = None, meanReturnPerTradePct: float | None = None, sharpeRatioPerTrade: float | None = None, maxDrawdownPct: float | None = None, portfolioValues: Optional[List[investfly.models.common.DatedValue]] = None)
netReturn: float | None = None
annualizedReturn: float | None = None
profitFactor: float | None = None
totalTrades: int | None = None
winRatioPct: float | None = None
avgProfitPerTradePct: float | None = None
avgLossPerTradePct: float | None = None
meanReturnPerTradePct: float | None = None
sharpeRatioPerTrade: float | None = None
maxDrawdownPct: float | None = None
portfolioValues: Optional[List[investfly.models.common.DatedValue]] = None
def toDict(self) -> Dict[str, Any]:
@staticmethod
def fromDict( jsonDict: Dict[str, Any]) -> PortfolioPerformance:
@dataclass
class OptionPositionGroup:

Group-level view used by strategy code (live + backtest).

Exit decisions (closeBeforeDte, profit/loss-based exits) are evaluated per-group rather than per-leg. The runtime fills legs from Java's reconciled open-position-group endpoint, not raw overlay table rows. Legs may include the underlying stock/ETF for buy-write structures that were opened atomically.

OptionPositionGroup( groupId: int, template: OptionStrategyTemplate, underlyingSymbol: str, contracts: Optional[int], netCreditAtOpen: Optional[float], openedAt: datetime.datetime, legs: List[OptionContractSnapshot] = <factory>)
groupId: int
underlyingSymbol: str
contracts: Optional[int]
netCreditAtOpen: Optional[float]
openedAt: datetime.datetime
def daysToEarliestExpiry(self, asOf: Optional[datetime.date] = None) -> Optional[int]:
@staticmethod
def fromDict( d: Dict[str, Any]) -> OptionPositionGroup:
@dataclass
class OptionContractSnapshot:

Per-leg view derived from a live open position matched to a persisted group leg.

Java persists only grouping keys. Price, quantity, contract unit, expiry, and option-right fields come from the currently-open broker/paper position and option symbol parsing.

OptionContractSnapshot( role: OptionLegRole, actionAtOpen: OptionLegAction, securityType: investfly.models.marketdata.SecurityType = OPTION, symbol: Optional[str] = None, quantity: Optional[float] = None, priceAtOpen: Optional[float] = None, contractUnits: Optional[int] = None, occSymbol: Optional[str] = None, underlyingSymbol: Optional[str] = None, optionType: Optional[investfly.models.marketdata.OptionType] = None, strikePrice: Optional[float] = None, expiry: Optional[datetime.date] = None, contracts: Optional[int] = None, openedAt: Optional[datetime.datetime] = None)
actionAtOpen: OptionLegAction
symbol: Optional[str] = None
quantity: Optional[float] = None
priceAtOpen: Optional[float] = None
contractUnits: Optional[int] = None
occSymbol: Optional[str] = None
underlyingSymbol: Optional[str] = None
optionType: Optional[investfly.models.marketdata.OptionType] = None
strikePrice: Optional[float] = None
expiry: Optional[datetime.date] = None
contracts: Optional[int] = None
openedAt: Optional[datetime.datetime] = None
@staticmethod
def fromDict( d: Dict[str, Any]) -> OptionContractSnapshot:
class OptionStrategyTemplate(builtins.str, enum.Enum):

Templated option structures supported by the Phase-1 MVP automated options engine.

Naked short calls/puts and any undefined-risk structure outside this list are rejected by validation. Each template prescribes a fixed leg count and action shape.

LONG_CALL = <OptionStrategyTemplate.LONG_CALL: 'LONG_CALL'>
LONG_PUT = <OptionStrategyTemplate.LONG_PUT: 'LONG_PUT'>
COVERED_CALL = <OptionStrategyTemplate.COVERED_CALL: 'COVERED_CALL'>
CASH_SECURED_PUT = <OptionStrategyTemplate.CASH_SECURED_PUT: 'CASH_SECURED_PUT'>
BULL_PUT_CREDIT_SPREAD = <OptionStrategyTemplate.BULL_PUT_CREDIT_SPREAD: 'BULL_PUT_CREDIT_SPREAD'>
BEAR_CALL_CREDIT_SPREAD = <OptionStrategyTemplate.BEAR_CALL_CREDIT_SPREAD: 'BEAR_CALL_CREDIT_SPREAD'>
BULL_CALL_DEBIT_SPREAD = <OptionStrategyTemplate.BULL_CALL_DEBIT_SPREAD: 'BULL_CALL_DEBIT_SPREAD'>
BEAR_PUT_DEBIT_SPREAD = <OptionStrategyTemplate.BEAR_PUT_DEBIT_SPREAD: 'BEAR_PUT_DEBIT_SPREAD'>
IRON_CONDOR = <OptionStrategyTemplate.IRON_CONDOR: 'IRON_CONDOR'>
CALL_BUTTERFLY = <OptionStrategyTemplate.CALL_BUTTERFLY: 'CALL_BUTTERFLY'>
PUT_BUTTERFLY = <OptionStrategyTemplate.PUT_BUTTERFLY: 'PUT_BUTTERFLY'>
CUSTOM_COMBO = <OptionStrategyTemplate.CUSTOM_COMBO: 'CUSTOM_COMBO'>
def isMultiLeg(self) -> bool:
def legCount(self) -> int:
def requiresStockUnderlyingPosition(self) -> bool:
def requiresCashCollateral(self) -> bool:
class OptionLegAction(builtins.str, enum.Enum):

str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.

BUY_TO_OPEN = <OptionLegAction.BUY_TO_OPEN: 'BUY_TO_OPEN'>
SELL_TO_OPEN = <OptionLegAction.SELL_TO_OPEN: 'SELL_TO_OPEN'>
BUY_TO_CLOSE = <OptionLegAction.BUY_TO_CLOSE: 'BUY_TO_CLOSE'>
SELL_TO_CLOSE = <OptionLegAction.SELL_TO_CLOSE: 'SELL_TO_CLOSE'>
def isOpen(self) -> bool:
def isBuy(self) -> bool:
class OptionLegRole(builtins.str, enum.Enum):

str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.

PRIMARY = <OptionLegRole.PRIMARY: 'PRIMARY'>
UNDERLYING = <OptionLegRole.UNDERLYING: 'UNDERLYING'>
PROTECTIVE_PUT = <OptionLegRole.PROTECTIVE_PUT: 'PROTECTIVE_PUT'>
PROTECTIVE_CALL = <OptionLegRole.PROTECTIVE_CALL: 'PROTECTIVE_CALL'>
SHORT_PUT = <OptionLegRole.SHORT_PUT: 'SHORT_PUT'>
LONG_PUT = <OptionLegRole.LONG_PUT: 'LONG_PUT'>
SHORT_CALL = <OptionLegRole.SHORT_CALL: 'SHORT_CALL'>
LONG_CALL = <OptionLegRole.LONG_CALL: 'LONG_CALL'>