[Financial Technology · Backend Engineering · Data Automation]
Trading Signal Intelligence Engine
An automated pipeline that reads cryptocurrency market data, narrows a wide universe of instruments down to qualified candidates and turns them into structured, validated trading signals.
01Project overview
The signal engine is the analytical core of Astra Raven. On a schedule it collects market data through external exchange APIs, evaluates the market context and runs every instrument through a sequence of filters before anything reaches a user.
The output is not a free-form opinion but a structured object — symbol, direction, entry zone, stop loss, targets and the reasons it passed — that downstream systems can store, track and evaluate.
02Engineering challenge
Market data is noisy and arrives from external services that can be slow, rate-limited or temporarily unavailable. The engine has to make consistent decisions under those conditions and leave a trail that explains each one.
- A
Process many instruments within a scheduled window without blocking on slow responses.
- B
Separate market context detection from per-instrument evaluation so each stage can be reasoned about on its own.
- C
Reject incomplete or contradictory candidates early instead of producing low-quality output.
- D
Store every signal with enough context to evaluate its outcome later.
03Solution architecture
Hover or tap each stage.
Market Data
Candles, volumes and instrument metadata are fetched from external exchange APIs with timeouts and retry limits.
04Main components
- 01
Data ingestion layer
Asynchronous collectors for market time series with request pacing, timeouts and graceful handling of partial responses.
- 02
Market context module
Classifies the current market state so later filters can adapt their behaviour to it.
- 03
Candidate ranking
Filters the instrument universe and ranks the remainder, keeping the pipeline fast and focused.
- 04
Validation chain
Ordered, individually testable checks. A candidate that fails any check is dropped with a recorded reason.
- 05
Signal persistence
SQL-backed storage of signals, their parameters and lifecycle, used by tracking and reporting.
- 06
Scheduler & reports
Scheduled execution, outcome tracking and diagnostic summaries for the operator.
05Technology stack
Core
- Python
- asyncio
- dataclasses
Data
- Exchange REST APIs
- Time-series processing
- SQLite / SQL
Operations
- Scheduled jobs
- Structured logging
- Reports
06Interactive demonstration
Simulated signal pipeline
IllustrativeIllustrative demo. Synthetic instrument and generated price data — no live market connection, no real strategy parameters and not a trading recommendation.
- Market Data
- Market Analysis
- Candidate Selection
- Signal Validation
- Risk Checks
- Signal Output
- Monitoring
$ press “Run pipeline” to process a synthetic market snapshot
Signal output
—
07Engineering decisions
- 01
Context before candidates
Evaluating the market state once, up front, keeps per-instrument logic simpler and makes the reasoning behind each signal easier to follow.
- 02
Fail early, record why
Each validation step can reject a candidate with an explicit reason. Fewer signals with clear provenance are worth more than many unexplained ones.
- 03
Structured output only
Signals are typed objects, not text. Delivery, tracking and reporting all consume the same structure.
- 04
Deterministic core
The decision path is rule-based and reproducible for the same inputs, which makes regressions detectable.
08Reliability & testing
- Timeouts and bounded retries around every external request.
- Validation of incoming data shape before it enters calculations.
- Regression checks when filter logic changes.
- Logs and reports that make a skipped or rejected instrument explainable.
09Code example
from dataclasses import dataclass, field
from typing import Callable
@dataclass
class Candidate:
symbol: str
direction: str # "LONG" | "SHORT"
entry: float
stop_loss: float
reasons: list[str] = field(default_factory=list)
Check = Callable[[Candidate], str | None] # returns a rejection reason or None
def has_valid_direction(c: Candidate) -> str | None:
return None if c.direction in {"LONG", "SHORT"} else "unknown direction"
def stop_on_correct_side(c: Candidate) -> str | None:
ok = c.stop_loss < c.entry if c.direction == "LONG" else c.stop_loss > c.entry
return None if ok else "stop loss on wrong side of entry"
CHAIN: list[Check] = [has_valid_direction, stop_on_correct_side]
def run_chain(c: Candidate) -> tuple[bool, str | None]:
for check in CHAIN:
if (reason := check(c)) is not None:
return False, f"{check.__name__}: {reason}"
c.reasons.append(check.__name__)
return True, NoneIllustrative Illustrative Engineering Example — a simplified validation chain, not production code.
Production source is private. Examples here show the engineering approach, not proprietary logic. More in the Engineering Lab.
10Possible extensions
- Pluggable data sources for additional venues or asset classes.
- Backtesting harness that replays stored market data through the same validation chain.
- Per-stage metrics dashboard showing where candidates are filtered out.