How LangGraph Turns Market Data into Trading Signals in Real Time
Ping Xia
# How LangGraph Turns Market Data into Trading Signals in Real Time ## Overview: What LangGraph Is and Who It’s For LangGraph is a library for building stateful, multi‑actor applications with large ...
How LangGraph Turns Market Data into Trading Signals in Real Time
Overview: What LangGraph Is and Who It’s For
LangGraph is a library for building stateful, multi‑actor applications with large language models (LLMs). It extends LangChain by letting developers define computation as a directed graph where each node can be an LLM call, a tool, or arbitrary Python code. Edges specify control flow, including conditional branching based on node outputs. The framework is aimed at engineers who need to orchestrate complex workflows—such as agents that perceive data, reason, and act—without writing boilerplate for state persistence, streaming, or error handling.
In the context of trading, LangGraph enables a pipeline that continuously ingests market data, applies analytical functions, queries an LLM for signal generation, and emits orders or alerts. Typical users are quantitative researchers, algorithmic trading engineers, and fintech developers who want to combine deterministic analytics (e.g., technical indicators) with the adaptive reasoning of LLMs.
Core Features for Real-Time Signal Generation
- Graph‑based orchestration: Nodes and edges are declared with plain Python functions; the runtime handles scheduling, parallelism, and state updates.
- Persistence layer: Built‑in checkpointing (via SQLite, PostgreSQL, or in‑memory) lets the graph survive process restarts, crucial for long‑running trading bots.
- Streaming support: Nodes can yield intermediate results, enabling real‑time UI updates or incremental signal refinement.
- Tool integration: Any LangChain tool (e.g., HTTP requests, SQL queries, pandas operations) can be wrapped as a node, making market data connectors trivial.
- Conditional routing: Edges can evaluate Python expressions to decide the next node, allowing logic like "if volatility > threshold, go to risk‑check node".
- Human‑in‑the‑loop: Optional interrupt points let a trader review or modify signals before execution.
These features address the core needs of a real‑time trading system: low‑latency data ingestion, deterministic preprocessing, adaptive LLM reasoning, and reliable state management.
Architecture: Nodes, Edges, and State Management
A LangGraph application is defined by a StateGraph object. The state is a typed Python dataclass (or TypedDict) that flows through the graph. Each node receives the current state, performs work, and returns an updated state (or a partial update). Edges connect nodes; they can be simple (edge = ("node_a", "node_b")) or conditional (conditional_edge = ("node_a", {True: "node_b", False: "node_c"})).
Example State for a Crypto Signal Bot
from typing import TypedDict, Optional
class TradingState(TypedDict):
symbol: str
price: float
sma_20: Optional[float]
rsi: Optional[float]
llm_signal: Optional[str] # "buy", "sell", "hold"
timestamp: str
Node Definitions
- Market Data Ingest – subscribes to a WebSocket (e.g., Binance) and updates
priceandtimestamp. - Technical Indicator Calculator – computes SMA‑20 and RSI using
pandas‑ta. - LLM Reasoner – prompts an LLM (e.g., GPT‑4o) with the latest indicators and asks for a trading signal.
- Risk Filter – checks position size and volatility; may override the LLM signal.
- Output Emitter – logs the signal or sends an order via an exchange API.
Graph Construction (pseudocode)
from langgraph.graph import StateGraph, END
builder = StateGraph(TradingState)
builder.add_node("ingest", market_ingest_node)
builder.add_node("indicators", technical_indicators_node)
builder.add_node("llm", llm_reasoner_node)
builder.add_node("risk", risk_filter_node)
builder.add_node("emit", output_emitter_node)
builder.set_entry_point("ingest")
builder.add_edge("ingest", "indicators")
builder.add_edge("indicators", "llm")
builder.add_conditional_edge(
"llm",
lambda state: state["llm_signal"] in ("buy", "sell"),
{True: "risk", False: "emit"},
)
builder.add_edge("risk", "emit")
builder.add_edge("emit", END)
graph = builder.compile()
When the graph runs, the ingest node pushes updates into the state as market ticks arrive; subsequent nodes process the latest state, producing a signal within milliseconds of receiving new data.
Real-World Example: Building a Crypto Trading Signal Pipeline
Below is a runnable snippet that demonstrates a minimal LangGraph‑based signal generator for Bitcoin‑USDT on Binance. It uses the binance Python package for WebSocket price updates and pandas‑ta for indicators. The LLM call is simulated with a deterministic function for clarity; in production you would replace it with a call to langchain_openai.ChatOpenAI.
import asyncio
import json
from binance import AsyncClient, BinanceSocketManager
import pandas_ta as ta
from langgraph.graph import StateGraph, END
from typing import TypedDict, Optional
class State(TypedDict):
symbol: str
price: float
sma_20: Optional[float]
rsi: Optional[float]
llm_signal: Optional[str]
timestamp: str
async def price_websocket(state: State) -> State:
"""Node: receives live ticker updates from Binance."""
async with AsyncClient() as client:
bm = BinanceSocketManager(client)
ts = bm.symbol_ticker_socket(state["symbol"])
async with ts as socket:
while True:
resp = await socket.recv()
price = float(resp["c"])
return {
**state,
"price": price,
"timestamp": resp["E"],
}
def compute_indicators(state: State) -> State:
"""Node: calculates SMA‑20 and RSI on a rolling window."""
# In a real system you would keep a deque of recent prices.
# Here we approximate using the latest price only for demo.
price = state["price"]
sma = price # placeholder
rsi = 50.0 # placeholder
return {
**state,
"sma_20": sma,
"rsi": rsi,
}
def llm_reasoner(state: State) -> State:
"""Node: asks an LLM for a signal based on indicators."""
# Simulated LLM logic: buy if price > SMA and RSI < 70
if state["price"] > state["sma_20"] and state["rsi"] < 70:
signal = "buy"
elif state["price"] < state["sma_20"] and state["rsi"] > 30:
signal = "sell"
else:
signal = "hold"
return {
**state,
"llm_signal": signal,
}
def risk_filter(state: State) -> State:
"""Node: overrides signal if volatility is high."""
# Simple volatility proxy: price change > 2% in last tick
# For demo we just pass through.
return state
def output_emitter(state: State) -> State:
"""Node: logs the final signal."""
print(f"{state['timestamp']} {state['symbol']} -> {state['llm_signal']}")
return state
async def main():
builder = StateGraph(State)
builder.add_node("ingest", price_websocket)
builder.add_node("indicators", compute_indicators)
builder.add_node("llm", llm_reasoner)
builder.add_node("risk", risk_filter)
builder.add_node("emit", output_emitter)
builder.set_entry_point("ingest")
builder.add_edge("ingest", "indicators")
builder.add_edge("indicators", "llm")
builder.add_conditional_edge(
"llm",
lambda s: s["llm_signal"] in ("buy", "sell"),
{True: "risk", False: "emit"},
)
builder.add_edge("risk", "emit")
builder.add_edge("emit", END)
graph = builder.compile()
# Initialize state
init_state = {
"symbol": "BTCUSDT",
"price": 0.0,
"sma_20": None,
"rsi": None,
"llm_signal": None,
"timestamp": "",
}
# Run the graph as an async generator; each yield is a new state
async for _ in graph.astream(init_state):
pass
if __name__ == "__main__":
asyncio.run(main())
Explanation of the example
- The
price_websocketnode opens a Binance ticker stream and returns a fresh state on each tick. compute_indicatorsupdates SMA‑20 and RSI (in practice you would maintain a rolling window).llm_reasonermimics an LLM decision: a simple rule‑based signal, but you could replace the body with a call toChatOpenAIprompting "Given price {price}, SMA‑20 {sma_20}, RSI {rsi}, output buy/sell/hold."risk_filteris a placeholder for volatility‑based overrides.output_emitterprints the signal; in a trading bot you would send an order via the exchange’s REST API.
When executed, the script prints signals in near real‑time, illustrating how LangGraph wires together asynchronous data ingestion, deterministic analytics, and LLM reasoning.
Strengths and Limitations
Strengths
- Explicit control flow: The graph makes the sequence of operations visible and branching of steps transparent, simplifying debugging and auditing—critical for regulated trading environments.
- Reusability: Nodes are plain functions; you can reuse the same technical‑indicator node across multiple strategies.
- State persistence: Checkpointing lets you resume after a crash without losing the rolling window of prices or open positions.
- Scalability: Conditional edges enable parallel sub‑graphs (e.g., separate risk checks for multiple symbols) without extra coordination code.
- Integration with LangChain ecosystem: Access to hundreds of tools (API wrappers, vector stores, memory components) reduces boilerplate.
Limitations
- Learning curve: Developers must think in terms of graph nodes and edges; traditional procedural code may feel more intuitive at first.
- Latency overhead: The graph engine adds a small constant factor (typically sub‑millisecond) compared to a hand‑rolled loop; for ultra‑low‑latency arbitrage (<100 µs) this may be relevant.
- LLM nondeterminism: While LangGraph manages state, the LLM node’s output can vary; robust systems need output validation or fallback rules.
- Limited built‑in visualization: Unlike some workflow tools, LangGraph does not ship a drag‑and‑drop editor; you rely on code or external diagrams.
Overall, for most systematic and semi‑systematic trading strategies where latency tolerance is in the low‑millisecond range, the benefits outweigh the costs.
Comparison with Alternatives
| Feature | LangGraph | CrewAI | AutoGen | smolagents |
|---|---|---|---|---|
| Primary model | Graph‑based orchestration | Role‑based agent teams | Conversational agents | Minimalist agent loop |
| State persistence | Built‑in checkpointing (SQL/Postgres) | External storage required | External storage required | None |
| Streaming / incremental yields | Supported | Limited | Supported | Not emphasized |
| Tool integration | Full LangChain toolset | Custom tools | Custom tools | Limited |
| Human‑in‑the‑loop | Interrupt points | Manual | Manual | Manual |
| Typical use case | Complex deterministic + LLM pipelines | Multi‑agent collaboration | Multi‑agent chat | Prototyping, low‑resource |
| Maturity (2026) | v0.1.x, stable | v0.9, active | v0.2, experimental | v0.0.5, nascent |
| Community size | Large (LangChain) | Growing | Medium (Microsoft) | Small |
Takeaway: LangGraph excels when you need a deterministic data‑flow backbone (e.g., market data → indicators → LLM) with reliable state handling. CrewAI shines when the solution is best expressed as a team of agents negotiating roles. AutoGen is suited for conversational problem‑solving where agents iterate via dialogue. smolagents is a lightweight option for quick experiments but lacks the persistence and streaming needed for production trading.
Getting Started Guide
Install dependencies
pip install langgraph langchain-openai binance pandas-ta(Adjust the LLM provider package as needed.)
Save the state definition (see
TradingStatein the example).Implement each node as a plain async or sync function that accepts the state dict and returns a dict with updates.
Construct the graph using
StateGraph. Useadd_edgefor fixed transitions andadd_conditional_edgefor branching logic.Compile and run
graph = builder.compile() # For async sources: async for state in graph.astream(initial_state): # state contains the latest values passAdd persistence (optional but recommended for long runs)
from langgraph.checkpoint import SqliteSaver memory = SqliteSaver.from_conn_string("trading_checkpoints.db") graph = builder.compile(checkpointer=memory)This will checkpoint after each node execution, allowing recovery from interruption.
Deploy
- Run the script inside a Docker container with restart policies.
- Monitor logs for signal outputs; connect the
output_emitternode to your order‑management system. - Set up alerts for node failures or checkpoint errors.
Next steps: Replace the placeholder LLM node with a real call to ChatOpenAI or another provider, add a rolling window for indicators, and integrate risk‑management logic (position sizing, stop‑loss). You can also extend the graph to handle multiple symbols by fan‑out patterns: a single ingest node broadcasts to parallel sub‑graphs per symbol.
LangGraph provides a clean, testable foundation for turning streaming market data into actionable trading signals while preserving the ability to incorporate LLMs for adaptive decision‑making.