Basics
This document explains the mental model and DSL overview of StockBeat.
Everything else in the system (signals, indicators, alarms) builds on the ideas explained here.
What is StockBeat?
StockBeat is a trading analysis and alerting platform designed to surface meaningful market insights and notify when predefined conditions are met.
Insights are expressed as signals, which are defined using a declarative domain-specific language (DSL) tailored for time-series market data.
Rather than writing imperative logic—loops, mutable state, or event callbacks—you declare conditions over aligned price and indicator data. StockBeat handles evaluation across both historical and live market data in a consistent, deterministic way.
You define what must be true, not how to compute it.
This approach enables:
- Clear and readable trading logic
- Reproducible backtests and alerts
- Reliable evaluation across timeframes and data sources
Core Mental Model
Everything Is a Series
The most important concept in StockBeat is a series.
A series represents a value that exists for every candle in time.
There are two fundamental kinds of series:
- Number Series → numeric value per candle
- Boolean Series → true / false per candle
Examples:
close() → number series
close().ema(20) → number series
close().rsi(14).lt(30) → boolean series
Number Series
Number series represent numeric data aligned with candles.
Examples include:
- Price dats
- Indicator outputs
- Derived numeric values
open()
high()
low()
close()
sma(50)
ema(20)
rsi(14)
Number series can be combined or transformed using arithmetic operators.
Learn more about Number Series
Boolean Series
Boolean series represent conditions evaluated per candle.
They answer the question:
“Is this condition true at this candle?”
Boolean series are produced by:
- Comparisons
- Crossovers
- Logical operators
Examples:
close().gt(open())
close().rsi(14).lt(30)
close().crosses_above(close().ema(20))
Learn more about Boolean Series
Expressions
An expression is any operation that produces a new series.
Key properties of expressions:
- Pure (no side effects)
- Immutable
- Deterministic
Evaluated per candle
Every expression returns a new series.
close().add(10)
close().mul(1.02)
Original series are never modified.
Chaining
Expressions are built using method chaining.
Chaining reads left-to-right and describes transformations step by step:
close().rsi(14).gt(70)
Which reads as:
“RSI with period 14 is greater than 70”
More complex example:
close()
.gt(close().ema(20))
.and(close().rsi(14).gt(50))
Arithmetic Operators
Arithmetic operators transform number series into number series.
Available operators:
- add
- sub
- mul
- div
Examples:
close().add(5)
close().sub(open())
close().mul(1.5)
close().div(close().ema(20))
Comparison Operators
Comparison operators transform number series into boolean series.
Examples:
gt // greater than
lt // less than
gte // greater than equal
lte // less than equal
eq // equal
neq // not equal
Usage:
Usage:
close().gt(open())
close().rsi(14).lt(30)
Logical Operators
Logical operators combine boolean series.
Available operators:
- and
- or
- not
Examples:
close().rsi(14).lt(30).and(close().gt(ema(200)))
Signals
A signal is simply a boolean series that represents intent.
Signals:
- Do not execute actions
- Do not send notifications
- Do not manage state
They only describe when something is true.
Examples:
rsi(14).lt(30)
close().crossesAbove(ema(20))
Signals are reusable and safe to backtest.
Alarms
An alarm reacts to a signal.
Conceptually:
Signal → Alarm → Action
Signals remain pure and deterministic. Alarms are responsible for side effects such as notifications or webhooks.
Time & Determinism
All expressions:
- Are evaluated per candle
- Produce the same result for the same input
- Can be replayed historically
This allows the same DSL definition to be used for:
- Backtesting
- Live alerts
- Historical analysis
Summary
- Everything is a series
- Expressions are pure and composable
- Signals describe truth, not actions
- Alarms handle effects
- The same definitions work for backtesting and live use
