Component · L2
Alpha Signals
github.com/juanmmm21/alpha-signal-generator
Pluggable strategy engine that emits strict entry and exit signals from market data.
- Lines
- 926
- Files
- 24
- Test files
- 6
- Commits
- 16
- Started
- 29 Jun 2026
- Last commit
- 6 Jul 2026
- Python 100%
● Where it sits
Layer 2 of Quant — analytics.
L1 Market data
L2 Analytics
L3 Backtest & execution
L4 Risk & audit
↳ Flagship
README · 2 min read
Commits per day
Decoupled strategy engine that analyzes OHLCV candles, technical indicators, and optional order book metrics to emit strict entry and exit events. Fifth module of the quant-core-infra ecosystem.
Repository: github.com/juanmmm21/alpha-signal-generator
What it is and what problem it solves
A trading bot needs to translate market data into discrete decisions: enter, exit, or hold. Mixing that logic with data ingestion, order execution, or backtesting produces fragile, untestable code.
This module isolates the decision logic behind a clear contract:
- Each strategy implements
evaluate(context) → SignalEvent - The engine maintains position state per strategy
- The output is a typed event with action, side, confidence, and reason
Adding a new strategy = one class + registration in registry.py. No need to touch the engine or the pipeline.
Role in quant-core-infra
market-data-lakehouse ──┐
ta-indicators-from-scratch ──► candles + indicators ──► alpha-signal-generator
order-book-reconstructor ──┘ (book metrics) │
▼
event-driven-backtester
It is the decision brain between data analysis and simulation/execution.
Objective
Demonstrates:
- Decoupled design with
Protocoland an abstract base class - Strict
SignalEventcontracts for downstream systems - Multi-source context (candles, indicators, book)
- JSONL ingestion compatible with upstream modules
Included strategies
| ID | Entry logic | Exit logic |
|---|---|---|
rsi_mean_reversion | RSI ≤ oversold threshold (30) | RSI ≥ neutral (50) or overbought (70) |
macd_crossover | MACD crosses above signal | MACD crosses below signal |
book_imbalance | Bid-heavy imbalance + tight spread | Imbalance falls below exit threshold |
All manage long positions only in this initial version.
How it works
- Ingestion: JSONL candles are loaded with OHLCV fields + optional indicators.
- Context: for each bar, a
StrategyContextis built with the current bar, previous bar, open position, and optional book. - Evaluation: each registered strategy produces a
SignalEvent. - State:
SignalEngineupdates internal position onenter/exit. - Output: the pipeline filters
holdevents and serializes only actionable signals.
SignalEvent contract
| Field | Values | Description |
|---|---|---|
action | enter, exit, hold | The strategy's decision |
side | long, short, null | Required on enter/exit |
confidence | 0.0 – 1.0 | Conviction of the signal |
reason | str | Auditable text of the decision |
reference_price | Decimal | Reference price (bar close) |
Architecture
Candles + indicators (JSONL)
│
├─ optional book metrics (JSONL)
▼
StrategyContext (bar, previous_bar, position, book)
│
▼
SignalEngine
├─ RsiMeanReversionStrategy
├─ MacdCrossoverStrategy
└─ OrderBookImbalanceStrategy
│
▼
SignalEvent
Components
| Module | Responsibility |
|---|---|
base.py | BaseStrategy with _enter, _exit, _hold helpers |
protocols.py | TradingStrategy protocol |
strategies/ | Concrete implementations |
engine.py | Position state and bar-by-bar evaluation |
registry.py | create_strategy(name) factory |
ingest.py / pipeline.py | JSONL → serialized signals |
Technical decisions
- Decimal for reference prices and book metrics
- float for TA indicators (produced upstream)
- One position per strategy — no netting between strategies
- Actionable output —
holdnever appears in the pipeline's JSON
How to add a strategy
from alpha_signal_generator.base import BaseStrategy
from alpha_signal_generator.models import SignalEvent, StrategyContext
from alpha_signal_generator.registry import STRATEGY_REGISTRY
class MyStrategy(BaseStrategy):
def evaluate(self, context: StrategyContext) -> SignalEvent:
# your logic here
return self._hold(context.bar, "waiting for setup")
STRATEGY_REGISTRY["my_strategy"] = MyStrategy
Requirements
- Python 3.11+
Installation
cd alpha-signal-generator
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
CLI usage
# List strategies
alpha-signal-generator list
# RSI mean reversion
alpha-signal-generator run \
--candles samples/btcusdt_candles_with_indicators.jsonl \
--symbol BTCUSDT \
--strategy rsi_mean_reversion
# With order book confirmation
alpha-signal-generator run \
--candles samples/btcusdt_candles_with_indicators.jsonl \
--books samples/btcusdt_book_metrics.jsonl \
--symbol BTCUSDT \
--strategy book_imbalance \
--output signals.json
JSONL formats
Candles with indicators
{
"open": 100.5,
"high": 101.0,
"low": 99.5,
"close": 100.8,
"volume": 12.0,
"event_time": "2024-01-01T12:00:00Z",
"rsi": 28.5,
"macd_line": -0.12,
"signal_line": -0.08
}
Extra fields (rsi, macd_line, etc.) are automatically parsed as indicators.
Book metrics
{
"symbol": "BTCUSDT",
"best_bid": "100.4",
"best_ask": "100.6",
"spread": "0.2",
"mid_price": "100.5",
"bid_depth": "12.5",
"ask_depth": "8.0",
"imbalance": 0.32,
"event_time": "2024-01-01T12:00:00Z"
}
Programmatic usage
from alpha_signal_generator import (
MacdCrossoverStrategy,
RsiMeanReversionStrategy,
SignalEngine,
run_signal_pipeline,
)
# Full pipeline from files
signals = run_signal_pipeline(
candles_path="candles.jsonl",
strategy_name="macd_crossover",
symbol="BTCUSDT",
)
# Manual engine with multiple strategies
engine = SignalEngine([
RsiMeanReversionStrategy(),
MacdCrossoverStrategy(),
])
Development
pytest -q
ruff check src tests
mypy src
Roadmap
- Short and hedging strategies
- Strategy composition (voting, weighting)
- Real-time integration with candle stream
License
MIT