Python module:
from scalarlib import strategy — available only in strategy agent codeProduct Overview
What Is a Strategy?
A strategy is an automated trading agent that connects to one of your brokerage accounts and trades on your behalf according to its logic. Each strategy:- Has its own cash allocation (initial capital you assign at creation)
- Maintains its own position book — completely isolated from other strategies
- Tracks its own NAV (net asset value) over time for performance reporting
- Runs on a schedule you define, executing Python code that uses the
strategymodule
Capital Model
Every strategy tracks three capital metrics:Seeding Positions
When creating a strategy, you can optionally seed it with positions you already hold at the broker. Instead of starting from zero and buying everything from scratch, the strategy claims existing shares and begins managing them immediately. This is useful when you already have a portfolio at your brokerage and want a strategy to take over management of some or all of those holdings. You specify which positions and how many shares to seed — the platform handles the rest. This works across all supported venues: equities on Alpaca, Polymarket outcome tokens, Jupiter DEX tokens, and long Hyperliquid positions (seeding is long-only; short perps cannot be seeded).Reconciliation at Approval
Before a strategy with seeded positions can go active, the platform runs a reconciliation check against your live broker state. This ensures everything is consistent before the strategy starts trading. The reconciliation verifies:- Positions exist at the broker. Each symbol you want to seed must be an actual holding in your brokerage account. If the symbol is not found, approval is rejected.
- Sufficient shares are available. The broker must hold at least as many shares as you want to seed. If you request 10 shares of AAPL but only hold 6, approval fails.
- Shares are not already claimed by other strategies. Since multiple strategies can share a brokerage account, the platform tracks which shares are “claimed” by each strategy. If another strategy on the same account has already claimed some of those shares, only the remaining unclaimed shares are available. If there aren’t enough unclaimed shares, approval fails with a message showing how many are already claimed.
- A live price can be resolved. The platform fetches a live price from the broker for each position. This is needed to compute the strategy’s starting capital. If the market is closed or the symbol is invalid and no price can be determined, approval fails.
initial_capital is computed as allocation + sum(qty x price) of all seeded positions. After seeding, strategy.state() immediately reflects the claimed positions — no trades are needed.
If any position fails reconciliation, the entire operation is rolled back. No positions are seeded and the strategy remains in a pending state so you can fix the issue and retry.
Reconciliation Errors
Immutability
Seeded positions can be adjusted freely while the strategy is still pending approval. Each edit re-validates against the broker. Once the strategy is approved and active, seeded positions and allocation are locked. To change them, delete the strategy and create a new one.Strategy Isolation
- Each strategy has its own rows in the platform’s position ledger, isolated by strategy identity.
- The platform sums all strategy positions to produce an aggregate and continuously reconciles it against the broker’s actual holdings (see Reconciliation).
- A strategy cannot read sibling strategies’ positions, cash, or trade history.
Order Execution
Strategies place trades by specifying a target position size for a symbol. The platform computes the required buy or sell delta, checks buying power, and routes the order to the brokerage.Strategy Lifecycle
NAV Tracking
Strategy NAV is computed ascash + sum(position market values) using live prices from the broker. Historical NAV is recorded over time, enabling performance charts, win rate calculations, and P&L summaries on the strategy detail page.
Strategy Functions Reference
Thestrategy module is available only inside strategy agent code (the manageAutomatedAgent tool). Do not use strategy.* in chat code execution — use venue.* instead.
All timestamps are in New York time, timezone-naive (format: "YYYY-MM-DD HH:MM:SS").
strategy.state()
Returns the current strategy snapshot. Reconciles all pending broker orders before returning, so positions and cash are always up to date.
Return Schema
Position fields:
Pending order fields:
strategy.execute()
Sets the target position for a single symbol. The platform computes the delta from the current position and places a broker order only if needed. Idempotent — calling execute("AAPL", 10) twice is a no-op the second time.
Parameters
Return Schema
On success (FILLED or PENDING):
On rejection (
BLOCKED or FAILED):
On
BLOCKED or FAILED, only status, symbol, and reason are present. Fields like delta, filled_qty, avg_price, and broker_order_id will be missing. Always use .get() to access these fields safely.Block / Rejection Reasons
strategy.liquidate()
Flattens strategy positions by calling execute(symbol, 0) for each symbol.
Parameters
Return Schema
strategy.cancel()
Cancels a pending broker order. Reconciles first to check if the order has already filled. If the order was partially filled, the filled portion is applied to positions and cash — only the unfilled remainder is cancelled.
Parameters
Return Schema
strategy.activity()
Returns the strategy’s event stream, sorted newest first.
Parameters
Event Kinds
Strategy Code Best Practices
When writing strategy agent code, follow these patterns to avoid common pitfalls: 1. Always check state before tradingexecute() takes a target position, not a delta
To increase a position, read the current quantity and add:
int()
int(285 / 400) returns 0, silently skipping the position. Use round():
strategy.state() as the source of truth
Never track positions, balances, or filled quantities in state.json. The broker is the source of truth, and strategy.state() reconciles with the broker before returning. After every execute() call, re-read state: