Strategy Canvas & Intelligence API
Strategy Canvas & Intelligence is the R&D API for defining, running, and analyzing trading strategies. Use this API to programmatically create rule-based strategy definitions (entry groups, exit controls, risk parameters), run backtests against historical market data, and monitor deployment health across backtest → paper → shadow → live phases. Built on FalkorDB (trading knowledge graph), ClickHouse (time-series), and PostgreSQL (relational state), this API serves strategy engineers, quant researchers, and live traders. All endpoints require authentication: Supabase JWT (Authorization: Bearer <token>) for users, or X-Internal-Secret header for service principals.
Base Path
X-Internal-Secret (service). Strict auth enforced in prod: missing credentials → 401 Unauthorized.
Strategy CRUD & Canvas
POST /strategies
Create a new strategy with rule-based entry/exit logic, risk controls, and optional visual canvas layout.- Parameters: none
- Request body:
StrategyCreate - Response 201:
StrategyResponse
strategy_versions table. If archetype is set and entry_groups is empty, injects preset rules + stop-loss configs for the archetype (momentum, trend_following, mean_reversion, volatility, or custom).
GET /strategies
List authenticated user’s strategies (paginated), optionally with latest backtest metrics.- Query parameters:
limit(integer, optional, default=20, max=100): Results per pageoffset(integer, optional, default=0): Pagination offsetinclude(string, optional): Passmetricsto join latest backtest results
- Response 200:
?include=metrics is present, each strategy includes latest_backtest (null if no runs). When absent, latest_backtest is omitted.
GET /strategies/
Get a single strategy by ID, optionally with latest backtest results.- Parameters:
strategy_id(path, required, UUID): Strategy IDinclude(query, optional): Passbacktestto include latest backtest run (includes equity curve)
- Response 200: Strategy object (same shape as POST response, but with optional
latest_backtestincludingequity_curvefield if requested)
GET /strategies//backtest-history
Get all backtest runs for a strategy, newest first.- Parameters:
strategy_id(path, required, UUID)limit(query, optional, default=20, max=50): Number of runs to return
- Response 200:
PUT /strategies/
Update a strategy. Increments version and records snapshots instrategy_versions if rules or risk_controls change.
- Parameters:
strategy_id(path, required, UUID)
- Request body:
StrategyUpdate(all fields optional) - Response 200:
StrategyResponse
DELETE /strategies/
Soft-delete a strategy (setsdeleted_at timestamp).
- Parameters:
strategy_id(path, required, UUID)
- Response 204: No content
Strategy Deployment & Promotion
GET /strategies//gates
Get promotion gate status for the current deployment phase.- Parameters:
strategy_id(path, required, UUID)
- Response 200:
- Must have run a backtest (result_row required)
- Backtest must have sufficient trade density for walk-forward validation (
oos_sharpe_poolednot null) - Pooled out-of-sample Sharpe ≥ 1.0
- Minimum 5 total trades
- At least one regime (from
regime_breakdown) with positive Sharpe - For options strategies: stricter thresholds
POST /strategies//promote
Promote a strategy to the next deployment phase if gates pass.- Parameters:
strategy_id(path, required, UUID)
- Request body: none
- Response 200:
StrategyResponsewith updateddeployment_phaseand (for live promotion)deployment_ramp_pct = 10
Strategy Health & Capacity
GET /strategy/health
Get current health snapshot of all 6 signal types (latest daily).- Parameters: none
- Response 200:
days_until_gate_failure < 180 (warning) or < 30 (critical).
GET /strategy/health//history
Get 90-day (or custom) health history for a single signal type.- Parameters:
signal_type(path, required): Signal type namedays(query, optional, default=90, max=365): Lookback window in days
- Response 200:
GET /strategy/capacity
Get capacity estimate: current utilization, max capital before Sharpe degrades to 1.0, binding constraint.- Parameters: none
- Response 200:
Strategy Pause/Resume (Trade Execution)
GET /trade/strategies/pauses
List all paused strategies (whether paused by session or indefinitely).- Parameters: none
- Response 200:
StrategyPauseListResponse
POST /trade/strategies//pause
Pause a strategy (session or indefinite).- Parameters:
strategy_id(path, required, UUID)
- Request body:
PauseStrategyRequest | null - Response 200:
StrategyPauseResponse
DELETE /trade/strategies//pause
Resume a paused strategy.- Parameters:
strategy_id(path, required, UUID)
- Response 204: No content (shape inferred from handler — likely returns
{status: "resumed"}or similar)
Strategy Matching & Recommendation
GET /stocks//strategies
Get matching trading strategies for a symbol based on current market conditions.- Parameters:
symbol(path, required): Stock ticker (e.g. “NVDA”)
- Response 200:
StrategyMatchResponse
Internal Acceptance & Registry
The following endpoints are for operator/QA only (/api/internal/... require X-Internal-Secret):
Key Schemas
StrategyRules
The core rule-engine encoding for entry and exit logic.RuleCondition (Entry/Exit Condition)
Encodes a single decision rule: compare a source value (indicator, price, graph field, etc.) against an operator and a value.- id (string | null): Stable canvas node ID (auto-assigned on first open, max 64 chars)
- source (
ConditionSource): Where the value comes fromindicator: Named technical indicator (RSI, MACD, ATR, EMAs, BBands, etc.)mse_signal: Real-time signal from Market Signal Engineprice_action: Price/VWAP/pivotsvolume: Volume profile, bar volume, relative volumeoptions: Options-derived (IV percentile, put/call ratios, unusual activity)graph_field: FalkorDB stock attribute (e.g.graph_field.iv_percentile_30d)stop_loss: Meta-condition for stop-loss rules (used in exit_groups; see StopLossConfig)time_exit: Time-of-day exit (HH:MM ET)
- indicator (string | null): Indicator name when source=indicator (e.g. “rsi_14”, “macd_12_26”, “atr_14”)
- field (string | null): Field name when source=price_action or graph_field (e.g. “close”, “vwap”, “iv_percentile_30d”)
- operator (
Operator): Comparison operatorgt,gte,lt,lte: Numeric comparisoneq,neq: Equalityin,not_in: List membershipcrosses_above,crosses_below: Crossing detection (requires 2-bar history)
- value (float | int | string | list | null): RHS of comparison. For
in/not_in, must be a list. Forcrosses_above/below, can be null (userefinstead). - ref (string | null): Alternative RHS: resolves to another indicator/field value
- Format:
indicator.<name>.<key>(e.g.indicator.rsi_14) orprice.<field>(e.g.price.vwap) orgraph_field.<field>
- Format:
- ref_offset (
RefOffset| null): Arithmetic offset applied toref(PR-3 feature, #944)op:+or-coef: Scaling factor (e.g. 2.0 for 2× ATR)ref: Offset value (e.g.indicator.atr_14)- Resolves to:
base_ref ± coef * offset_ref(e.g.price.vwap + 2.0 * indicator.atr_14)
- params (object | null): Indicator-specific params (e.g.
{period: 14, threshold: 0.7}) - type (string | null): Semantic type hint for canvas rendering (e.g. “overbought”, “breakout”)
- update_frequency (string | null): How often the condition is evaluated (“tick”, “bar”, “daily”, etc.)
- staleness_warn_sec (integer | null): Alert if condition value is older than N seconds
RiskControls
Position sizing, stop-loss configuration, and portfolio limits.atr: ATR-based trailing stop. Params:multiplier(number)trailing: Activates after return threshold; locks in gains. Params:atr_multiple,activation_rtarget: Exit when profit reaches N ATRs. Params:target_atr(number)conviction_drop: Exit if entry conviction signal drops below threshold. Params:threshold(number)regime_flip: Exit if market regime shifts to hostile (e.g. from BULLISH to VOLATILE_SELLOFF). Params:exit_regimes(list of regime names)time: Exit at fixed ET time-of-day (EOD, etc.). Params:time_et(HH:MM string)
UniverseConfig
Defines which symbols/sectors a strategy trades.ContractSelectionConfig
Rule-based or specific contract picker for options strategies. RuleBasedContractConfig (parameterized rules):CanvasLayoutPersisted
Visual canvas state (node positions, viewport, active group).<group_id>:<condition_index> for conditions, stoploss:<index> for stops. Columns are: signal, filter, hub, exit.
StrategyCreate
Request to POST /strategies.StrategyResponse
Returned by GET/PUT/POST (all CRUD + promote).StrategyMatchResponse
Returned by GET /stocks//strategies. Hardcoded strategy dict evaluated against real-time indicators.Enumerations
Instrument:stocks, options, both
Timeframe: scalping, intraday, swing
Archetype: mean_reversion, trend_following, momentum, volatility, custom
AutomationLevel: monitor (alerts only), supervised (requires approval), autonomous (self-executing)
DeploymentPhase: backtest, paper, shadow, live
ConditionSource: indicator, mse_signal, price_action, volume, options, graph_field, stop_loss, time_exit
Operator: gt, gte, lt, lte, eq, neq, in, not_in, crosses_above, crosses_below
Example Full Strategy JSON
Notes for Strategy Engineers
- Preset rules: When creating with
archetype != customand emptyentry_groups, the API injects rules fromARCHETYPE_PRESETS(e.g., momentum archetype gets RSI 70/30 + volume filters). Caller’srisk_controls(sizing, position limits) are preserved; only stop losses are merged if not already present. - Versioning: Strategy versions are snapshots in the
strategy_versionstable, keyed on(strategy_id, version). Incremented wheneverrulesorrisk_controlschange (via PUT). Querystrategy_versionsto audit rule evolution. - Canvas persistence: Node positions, viewport zoom, and active group are stored in
canvas_layoutJSONB. IDs are stable across edits (auto-assigned on first open if missing). - Rule validation: All rules are validated at the Pydantic layer (bounds on list lengths, string lengths, numeric ranges) and then by
RuleValidator(semantic checks: at least one entry, at least one exit, no cross-references to missing indicators). - Phase gates: Backtest→paper gates are automated (
oos_sharpe_pooled ≥ 1.0, regime diversity, etc.). Paper→shadow and shadow→live require human approval + operator intent. - Backtests: Strategies are tested on-the-fly (no separate tape rebuild needed) by the backtest engine, which sources
market_data_1minand aggregates to the requested timeframe. Results are persisted instrategy_backtest_resultswith metrics (Sharpe, win rate, drawdown, regime breakdown, equity curve).