Skip to main content

LseTick

Struct LseTick 

Source
pub struct LseTick {
    pub subscription_id: SubscriptionId,
    pub time_exchange: DateTime<Utc>,
    pub price: Decimal,
    pub bid: Option<Decimal>,
    pub ask: Option<Decimal>,
    pub volume: Decimal,
    pub replay: bool,
}
Expand description

A tick published on the London Strategic Edge WebSocket.

One frame shape serves every dataset — FX, crypto, equities, ETFs, indices, commodities, futures, volatility, currency indices and interest rates all publish the same seven keys. This is the opposite of the provider’s bulk-export path, where the column set varies per dataset.

{"type":"tick","symbol":"BTC/USD","ts":"2026-01-02T09:37:24.760146+00:00",
 "price":42000.5,"bid":42000.5,"ask":42001.0,"volume":0.00155}

§⚠️ The tick is a QUOTE, not a print — except on the options channel

price equals bid exactly — measured on 3,966 of 3,966 sampled ticks spanning every dataset family, plus every sample taken on the provider’s other price endpoint. Anything decoded from this frame as a trade is therefore a bid-side quote wearing a trade’s shape, and is not evidence that a transaction occurred at that price or at all. See the trade transformer for what ships anyway and why.

§Option contract ticks differ in four ways

Option contracts tick on this same frame, under their OSI symbol (SPY260930C00700000):

  • bid and ask are null on every one, while an equity tick on the same connection in the same second carries both. It is a property of the channel, not of market hours, so an option contract has no quote here at all — bid and ask are optional for this reason alone.
  • The tick is a real print. Over one identical window every option tick matched a row of the provider’s REST option-print tape exactly on (price, volume), and vice versa. The quote caveat above does not apply to it.
  • ts is whole-second. Dozens of prints share one value, so an option tick’s instant is neither a unique key nor an ordering: arrival order is the only sequencing, and it was never observed out of order.
  • An extra name key carries a human-readable contract label. It is present on every live option tick, so it marks the channel and says nothing about replay — only replay does that. It is not decoded.

§⚠️ volume is real on some datasets and fabricated on others

Crypto and equity ticks carry a genuine per-tick size: summing it over three whole minutes of one crypto symbol reproduced the provider’s own one-minute candle volume to the last decimal, ratio 1.000. FX and commodity ticks carry a hard-coded 1.0 on every tick of every symbol sampled — a fabricated size, not a measured one, and it will aggregate into a legitimate-looking total at any resolution. Note this differs from the provider’s REST vault, which omits FX volume entirely; the WebSocket invents a value instead.

§⚠️ Identical consecutive ticks are REAL and must not be filtered

Ticks routinely repeat a prior (ts, price, bid, ask, volume) signature — barely a third of a sampled run was unique, and one signature recurred 49 times. They are nonetheless distinct prints: de-duplicating them destroyed 3–10% of the volume that reconciles exactly against the provider’s candles. This is an aggregated cross-venue tape on which identical-size fills at the same millisecond are ordinary. Do not add a de-duplication filter.

§The four Decimal fields carry ~15 significant digits, not arbitrary precision

This feed sends prices as JSON numbers rather than as strings — it is the only connector in this crate that does — so they are parsed as f64 before reaching Decimal. The ceiling is therefore the f64’s: 15 significant digits survive exactly, and a 17-digit literal like 10.123456789012345 lands as 10.123456789012344. The provider’s own tick shapes (42000.5, 0.00155, 16.9) are nowhere near that, so no observed value loses a digit.

The same ceiling applies on the bulk-export path for the same reason, where it is pinned by an_equity_row_deserializes_float_prices_and_an_integer_volume in historical.

Reading the provider’s digits instead of the f64 is not available here, and that is structural rather than an omission: LseMessage is internally tagged, so serde buffers the frame body into its Content type before this struct is deserialised, and Content stores a JSON number as an already-parsed f64. A raw-text deserialiser — serde_json::value::RawValue — cannot be driven from that buffer at all, for the same reason a borrowed &str symbol cannot (see de_tick_subscription_id). Recovering the digits would mean giving up the derived tagging for a hand-written dispatch on the crate’s central wire enum.

Fields§

§subscription_id: SubscriptionId

Subscription identifier built from symbol during deserialisation.

Constructing it here keeps the per-tick format! out of the transformer’s hot path, and mirrors how every other WebSocket integration in this crate resolves a frame to its instrument.

§time_exchange: DateTime<Utc>

The instant the provider stamped the tick with.

§The three spellings, all measured on one connection

  1. RFC 3339 — 2026-01-02T09:37:24.760146+00:00.
  2. The same with a space separating date and time — 2026-01-02 09:37:21.690159+00:00, which is what five of thirteen sampled dataset families send. DateTime::parse_from_rfc3339 accepts it: RFC 3339 §5.6 permits a space in place of the T by prior agreement, and chrono implements that lenience — verified against both 0.4.39, the oldest this workspace admits, and the pinned 0.4.45. It is a lenience rather than a guarantee, so a_space_separated_timestamp_decodes_to_the_same_instant_as_the_t_form pins it: a future chrono that tightened the grammar would fail the build rather than silently drop five dataset families.
  3. Epoch seconds as a JSON number — 1786091921.387. Replayed ticks use this while live ticks on the same connection use a string, so the field changes JSON type mid-stream. A decoder typed as a string fails the moment replay is enabled.

Sub-second precision also varies per symbol within one spelling: microseconds, milliseconds, and — on at least one symbol — no fractional component at all.

§Every spelling is quantised to microseconds

An f64 cannot carry nanosecond resolution at epoch scale: near the present its spacing is roughly a quarter of a microsecond, so nanoseconds recovered from spelling 3 are noise. Rounding to the nearest microsecond discards that noise and recovers the provider’s own precision exactly, which matters for more than tidiness — it is what makes the three spellings of one instant decode to the same value. The replay path re-sends ticks the live path already delivered, in a different spelling, so anything comparing the two for equality (resume arithmetic above all) depends on them agreeing.

The string spellings are quantised to that same resolution rather than passed through at whatever they carry, so the agreement is enforced rather than observed. Every string sampled carried at most six fractional digits, but a seventh would defeat the resume comparison silently: the watermark would hold a sub-microsecond instant, start would go out truncated to the microsecond below it, and every replayed tick at that instant would then sort before the watermark and be re-emitted as a duplicate.

A string that is neither spelling, including one carrying no UTC offset, is rejected rather than guessed at — a mis-parsed timestamp is a silently misdated market event.

§price: Decimal

The tick price. Equal to bid on every non-option sample taken, and the traded premium on an option contract; see the type-level note, which also covers the ~15-significant-digit ceiling this and the three fields below decode under.

§bid: Option<Decimal>

The bid. None on every option contract tick, which the provider publishes as null; present on every other dataset sampled.

§ask: Option<Decimal>

The ask. None on every option contract tick, which the provider publishes as null; present on every other dataset sampled.

§volume: Decimal

The size traded at this tick — genuine on crypto and equities, fabricated on FX and commodities. See the type-level note.

§replay: bool

Whether the tick was served from the historical replay buffer rather than live.

The provider sets this only on replayed ticks; live ticks carry no replay key at all, so absence means live and the default is load-bearing rather than cosmetic.

Trait Implementations§

Source§

impl Clone for LseTick

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for LseTick

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for LseTick

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Eq for LseTick

Source§

impl PartialEq for LseTick

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for LseTick

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> AttachedTransformer<()> for T

Source§

fn attached(&mut self, _: ())

Take what the connection handed the stream on attaching.
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> Conv for T

Source§

fn conv<T>(self) -> T
where Self: Into<T>,

Converts self into T using Into<T>. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> FmtForward for T

Source§

fn fmt_binary(self) -> FmtBinary<Self>
where Self: Binary,

Causes self to use its Binary implementation when Debug-formatted.
Source§

fn fmt_display(self) -> FmtDisplay<Self>
where Self: Display,

Causes self to use its Display implementation when Debug-formatted.
Source§

fn fmt_lower_exp(self) -> FmtLowerExp<Self>
where Self: LowerExp,

Causes self to use its LowerExp implementation when Debug-formatted.
Source§

fn fmt_lower_hex(self) -> FmtLowerHex<Self>
where Self: LowerHex,

Causes self to use its LowerHex implementation when Debug-formatted.
Source§

fn fmt_octal(self) -> FmtOctal<Self>
where Self: Octal,

Causes self to use its Octal implementation when Debug-formatted.
Source§

fn fmt_pointer(self) -> FmtPointer<Self>
where Self: Pointer,

Causes self to use its Pointer implementation when Debug-formatted.
Source§

fn fmt_upper_exp(self) -> FmtUpperExp<Self>
where Self: UpperExp,

Causes self to use its UpperExp implementation when Debug-formatted.
Source§

fn fmt_upper_hex(self) -> FmtUpperHex<Self>
where Self: UpperHex,

Causes self to use its UpperHex implementation when Debug-formatted.
Source§

fn fmt_list(self) -> FmtList<Self>
where &'a Self: for<'a> IntoIterator,

Formats each item in a sequence. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> JsonSchemaMaybe for T

Source§

impl<T> Pipe for T
where T: ?Sized,

Source§

fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> R
where Self: Sized,

Pipes by value. This is generally the method you want to use. Read more
Source§

fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> R
where R: 'a,

Borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> R
where R: 'a,

Mutably borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
where Self: Borrow<B>, B: 'a + ?Sized, R: 'a,

Borrows self, then passes self.borrow() into the pipe function. Read more
Source§

fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
where Self: BorrowMut<B>, B: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.borrow_mut() into the pipe function. Read more
Source§

fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
where Self: AsRef<U>, U: 'a + ?Sized, R: 'a,

Borrows self, then passes self.as_ref() into the pipe function.
Source§

fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
where Self: AsMut<U>, U: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.as_mut() into the pipe function.
Source§

fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
where Self: Deref<Target = T>, T: 'a + ?Sized, R: 'a,

Borrows self, then passes self.deref() into the pipe function.
Source§

fn pipe_deref_mut<'a, T, R>( &'a mut self, func: impl FnOnce(&'a mut T) -> R, ) -> R
where Self: DerefMut<Target = T> + Deref, T: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.deref_mut() into the pipe function.
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> Tap for T

Source§

fn tap(self, func: impl FnOnce(&Self)) -> Self

Immutable access to a value. Read more
Source§

fn tap_mut(self, func: impl FnOnce(&mut Self)) -> Self

Mutable access to a value. Read more
Source§

fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Immutable access to the Borrow<B> of a value. Read more
Source§

fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Mutable access to the BorrowMut<B> of a value. Read more
Source§

fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Immutable access to the AsRef<R> view of a value. Read more
Source§

fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Mutable access to the AsMut<R> view of a value. Read more
Source§

fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Immutable access to the Deref::Target of a value. Read more
Source§

fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Mutable access to the Deref::Target of a value. Read more
Source§

fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self

Calls .tap() only in debug builds, and is erased in release builds.
Source§

fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self

Calls .tap_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Calls .tap_borrow() only in debug builds, and is erased in release builds.
Source§

fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Calls .tap_borrow_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Calls .tap_ref() only in debug builds, and is erased in release builds.
Source§

fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Calls .tap_ref_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Calls .tap_deref() only in debug builds, and is erased in release builds.
Source§

fn tap_deref_mut_dbg<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Calls .tap_deref_mut() only in debug builds, and is erased in release builds.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> TryConv for T

Source§

fn try_conv<T>(self) -> Result<T, Self::Error>
where Self: TryInto<T>,

Attempts to convert self into T using TryInto<T>. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more