#[non_exhaustive]pub struct Signal {Show 13 fields
pub direction: SignalDirection,
pub strength: SignalStrength,
pub timestamp: i64,
pub price: f64,
pub reason: Option<String>,
pub metadata: Option<SignalMetadata>,
pub tags: Vec<String>,
pub scale_fraction: Option<f64>,
pub order_type: OrderType,
pub expires_in_bars: Option<usize>,
pub bracket_stop_loss_pct: Option<f64>,
pub bracket_take_profit_pct: Option<f64>,
pub bracket_trailing_stop_pct: Option<f64>,
}Expand description
A trading signal generated by a strategy
Fields (Non-exhaustive)§
This struct is marked as non-exhaustive
Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.direction: SignalDirectionSignal direction
strength: SignalStrengthSignal strength/confidence
timestamp: i64Timestamp when signal was generated
price: f64Price at signal generation
reason: Option<String>Optional reason/description
metadata: Option<SignalMetadata>Strategy-specific metadata (indicator values, etc.)
User-defined tags for post-hoc trade subgroup analysis.
Tags are propagated to [Trade::tags] when a position closes,
enabling BacktestResult::trades_by_tag and metrics_by_tag queries.
Use the .tag() builder to attach tags at signal creation time.
scale_fraction: Option<f64>Fraction for SignalDirection::ScaleIn and SignalDirection::ScaleOut signals.
ScaleIn: fraction of current portfolio equity to add to the position (0.0..=1.0).ScaleOut: fraction of current position quantity to close (0.0..=1.0).
None for all other signal directions. Set via Signal::scale_in /
Signal::scale_out constructors.
order_type: OrderTypeOrder type controlling how this signal’s entry is executed.
OrderType::Market (default) fills at next bar’s open. Limit and
stop types queue the order as a PendingOrder and fill when the
bar’s high/low reaches the specified price level.
Only meaningful for SignalDirection::Long and
SignalDirection::Short signals; ignored for Exit / ScaleIn /
ScaleOut / Hold.
expires_in_bars: Option<usize>Expiry for pending limit/stop orders, measured in bars.
When set, the pending order is cancelled if not filled within this
many bars after it is placed. None means Good-Till-Cancelled.
Only relevant when Signal::order_type is not OrderType::Market.
bracket_stop_loss_pct: Option<f64>Per-trade stop-loss percentage override (0.0 – 1.0).
When set on an entry signal (SignalDirection::Long or
SignalDirection::Short), this value is stored on the resulting
Position and takes precedence over BacktestConfig::stop_loss_pct
for the lifetime of that position.
Set via the .stop_loss(pct) builder method.
bracket_take_profit_pct: Option<f64>Per-trade take-profit percentage override (0.0 – 1.0).
When set on an entry signal, stored on the resulting Position and
takes precedence over BacktestConfig::take_profit_pct.
Set via the .take_profit(pct) builder method.
bracket_trailing_stop_pct: Option<f64>Per-trade trailing stop percentage override (0.0 – 1.0).
When set on an entry signal, stored on the resulting Position and
takes precedence over BacktestConfig::trailing_stop_pct.
Set via the .trailing_stop(pct) builder method.
Implementations§
Source§impl Signal
impl Signal
Sourcepub fn is_scaling(&self) -> bool
pub fn is_scaling(&self) -> bool
Check if this is a scaling signal (scale-in or scale-out)
Sourcepub fn scale_in(fraction: f64, timestamp: i64, price: f64) -> Self
pub fn scale_in(fraction: f64, timestamp: i64, price: f64) -> Self
Create a scale-in signal — add to an existing position.
fraction is the portion of current portfolio equity to allocate to
the additional shares. Must be in 0.0..=1.0; values outside this range
are clamped by the engine. Has no effect if no position is currently open.
§Example
use finance_query::backtesting::Signal;
// In a custom Strategy::on_candle implementation:
// Add 10% of current equity to the existing long position.
let signal = Signal::scale_in(0.10, ctx_timestamp, ctx_price);Sourcepub fn scale_out(fraction: f64, timestamp: i64, price: f64) -> Self
pub fn scale_out(fraction: f64, timestamp: i64, price: f64) -> Self
Create a scale-out signal — partially exit an existing position.
fraction is the portion of the current position quantity to close.
Must be in 0.0..=1.0; values outside this range are clamped. A fraction
of 1.0 closes the entire position (equivalent to Signal::exit). Has
no effect if no position is currently open.
§Example
use finance_query::backtesting::Signal;
// In a custom Strategy::on_candle implementation:
// Close half the current position to lock in partial profits.
let signal = Signal::scale_out(0.50, ctx_timestamp, ctx_price);Sourcepub fn buy_limit(timestamp: i64, price: f64, limit_price: f64) -> Self
pub fn buy_limit(timestamp: i64, price: f64, limit_price: f64) -> Self
Create a limit buy order — enter long when price pulls back to limit_price.
The order is queued as a PendingOrder and fills on the first subsequent
bar where candle.low ≤ limit_price. Fill price is limit_price, or the
bar’s open if a gap-down open is already below the limit (realistic gap fill).
§Example
use finance_query::backtesting::Signal;
// Buy if price dips to 98 within the next 5 bars.
let signal = Signal::buy_limit(ts, close, 98.0).expires_in_bars(5);Sourcepub fn buy_stop(timestamp: i64, price: f64, stop_price: f64) -> Self
pub fn buy_stop(timestamp: i64, price: f64, stop_price: f64) -> Self
Create a stop buy order (breakout entry) — enter long when price breaks above
stop_price.
Fills on the first subsequent bar where candle.high ≥ stop_price. Fill
price is stop_price, or the bar’s open if a gap-up open is already above
the stop (open price used instead).
§Example
use finance_query::backtesting::Signal;
// Enter long on a breakout above 105.
let signal = Signal::buy_stop(ts, close, 105.0);Sourcepub fn sell_limit(timestamp: i64, price: f64, limit_price: f64) -> Self
pub fn sell_limit(timestamp: i64, price: f64, limit_price: f64) -> Self
Create a limit sell order — enter short when price rallies to limit_price.
Fills on the first subsequent bar where candle.high ≥ limit_price. Fill
price is limit_price, or the bar’s open if a gap-up open is already at or
above the limit.
§Example
use finance_query::backtesting::Signal;
// Short into a rally reaching 103.
let signal = Signal::sell_limit(ts, close, 103.0).expires_in_bars(10);Sourcepub fn sell_stop(timestamp: i64, price: f64, stop_price: f64) -> Self
pub fn sell_stop(timestamp: i64, price: f64, stop_price: f64) -> Self
Create a stop sell order (breakdown entry) — enter short when price breaks
below stop_price.
Fills on the first subsequent bar where candle.low ≤ stop_price. Fill
price is stop_price, or the bar’s open if a gap-down open is already below
the stop.
§Example
use finance_query::backtesting::Signal;
// Short on a breakdown below 95.
let signal = Signal::sell_stop(ts, close, 95.0);Sourcepub fn buy_stop_limit(
timestamp: i64,
price: f64,
stop_price: f64,
limit_price: f64,
) -> Self
pub fn buy_stop_limit( timestamp: i64, price: f64, stop_price: f64, limit_price: f64, ) -> Self
Create a stop-limit buy order — triggered by a breakout above stop_price
but capped at limit_price.
Fills when candle.high ≥ stop_price and the computed trigger price
(bar open or stop_price, whichever is higher) does not exceed limit_price.
If the bar gaps up above limit_price, the order cannot fill that bar and
remains pending.
§Example
use finance_query::backtesting::Signal;
// Breakout buy above 105, but reject fills above 107.
let signal = Signal::buy_stop_limit(ts, close, 105.0, 107.0);Sourcepub fn expires_in_bars(self, bars: usize) -> Self
pub fn expires_in_bars(self, bars: usize) -> Self
Set an expiry (in bars) for this pending limit/stop order.
When the order is not filled within bars bars after being placed, it is
automatically cancelled. Has no effect on OrderType::Market signals.
§Example
use finance_query::backtesting::Signal;
// Day order: fill or cancel after 1 bar.
let signal = Signal::buy_limit(ts, close, 98.0).expires_in_bars(1);Sourcepub fn with_strength(self, strength: SignalStrength) -> Self
pub fn with_strength(self, strength: SignalStrength) -> Self
Set signal strength
Sourcepub fn with_reason(self, reason: impl Into<String>) -> Self
pub fn with_reason(self, reason: impl Into<String>) -> Self
Set reason/description
Sourcepub fn with_metadata(self, metadata: SignalMetadata) -> Self
pub fn with_metadata(self, metadata: SignalMetadata) -> Self
Set metadata
Sourcepub fn tag(self, name: impl Into<String>) -> Self
pub fn tag(self, name: impl Into<String>) -> Self
Attach a tag to this signal for post-hoc trade subgroup analysis.
Tags are propagated to [Trade::tags] when the position closes,
enabling BacktestResult::trades_by_tag and metrics_by_tag queries.
Multiple tags can be chained: .tag("breakout").tag("high_volume").
Sourcepub fn stop_loss(self, pct: f64) -> Self
pub fn stop_loss(self, pct: f64) -> Self
Attach a per-trade stop-loss to this entry signal.
pct is the loss fraction relative to the entry price (0.0..=1.0).
When set, the resulting position’s stop-loss overrides
BacktestConfig::stop_loss_pct for the lifetime of that trade.
§Example
use finance_query::backtesting::Signal;
// Stop out at -5% from entry, regardless of the config default.
let signal = Signal::long(ts, price).stop_loss(0.05);Sourcepub fn take_profit(self, pct: f64) -> Self
pub fn take_profit(self, pct: f64) -> Self
Attach a per-trade take-profit to this entry signal.
pct is the profit fraction relative to the entry price (0.0..=1.0).
When set, the resulting position’s take-profit overrides
BacktestConfig::take_profit_pct for the lifetime of that trade.
§Example
use finance_query::backtesting::Signal;
// Take profit at +15% from entry.
let signal = Signal::long(ts, price).take_profit(0.15);Sourcepub fn trailing_stop(self, pct: f64) -> Self
pub fn trailing_stop(self, pct: f64) -> Self
Attach a per-trade trailing stop to this entry signal.
pct is the trail fraction from the position’s peak/trough price
(0.0..=1.0). When set, the resulting position’s trailing stop
overrides BacktestConfig::trailing_stop_pct for the lifetime of
that trade.
§Example
use finance_query::backtesting::Signal;
// Exit if price drops 3% from its peak since entry.
let signal = Signal::long(ts, price).trailing_stop(0.03);Trait Implementations§
Source§impl<'de> Deserialize<'de> for Signal
impl<'de> Deserialize<'de> for Signal
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Auto Trait Implementations§
impl Freeze for Signal
impl RefUnwindSafe for Signal
impl Send for Signal
impl Sync for Signal
impl Unpin for Signal
impl UnsafeUnpin for Signal
impl UnwindSafe for Signal
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more