Create signal
POST/api/v1/signals
Create a new trading signal. Accepts JWT (web UI) or API Key with signals:write scope (automation).
The executeMode field controls processing behaviour:
- immediate: signal is processed and order placed right away.
- scheduled: signal is queued and processed at scheduledProcessAt. Requires scheduledProcessAt and timezone.
UTM is a translation layer. The caller owns intent and dedup. UTM refuses only signals the broker would reject. A same-direction signal for an (account, strategy, symbol, action) that already has a live (queued, processing, transmitted) signal is rejected with HTTP 409 and code DUPLICATE_INTENT (response details carries conflictingSignalId). See docs/developer/decisions.md.
Cross-field validation rules:
- scheduledProcessAt is required when executeMode is "scheduled".
- timezone is required when scheduledProcessAt or validUntil is set.
- limitPrice is required for limit and stopLimit orders.
- stopPrice is required for stop and stopLimit orders.
- exitTriggerMinutes is required when exitTriggerType is minutesAfterEntry or minutesBeforeClose.
- exitTriggerTime is required when exitTriggerType is atClockTime.
- MOC exit orders require exitTimeInForce: cls and a 15-minute minimum when paired with minutesBeforeClose.
Request
Responses
- 201
- 202
- 400
- 401
- 404
- 409
- 500
- 503
Signal created. Status depends on executeMode and broker response.
Signal accepted and scheduled for future processing
Request rejected by a domain rule. Possible code values:
VALIDATION_ERROR- request body failed schema validationSTRATEGY_INACTIVE- strategy exists but is deactivated; activate it before retryingPRECONDITION_FAILED- missing input the chosen executeMode requires (e.g. scheduledProcessAt for scheduled mode)SIGNAL_NOT_TRANSMITTED- signal was created but immediately moved to cancelled or error status
Authentication required (JWT or API key)
Account or strategy not found, or caller does not own it (code: NOT_FOUND)
Conflict.
code: DUPLICATE_INTENT- a same-direction live signal (queued, processing, or transmitted) already exists for this (accountId, strategyId, symbol, action). Response details carriesconflictingSignalId. Resolve the existing signal before submitting another.code: OPPOSING_POSITION_OPEN- the signal would open the opposing side of an existing non-terminal trade for the same(account, symbol)on a netting broker (Alpaca, TradeStation). Response details carriesconflictingTradeId. Close the conflicting trade to flat first, or route the strategy to a different account.code: REPLACE_REJECTED- cancellation refused because the associated order has already partially or fully filled at the broker; cancel the position manually.
Unexpected server error (code: INTERNAL_ERROR)
A required backing service is unavailable. code: SERVICE_UNAVAILABLE when scheduled signals are requested but the scheduler queue is disabled.