This page documents the Live utility class and its methods for executing real-time trading operations. The Live Trading API provides an infinite async generator that continuously monitors market conditions and executes strategy signals in real-time, with built-in crash recovery capabilities through state persistence. For historical simulation, see Backtest API. For strategy comparison, see Walker API. For event monitoring, see Event Listeners.
The Live object is a singleton instance of LiveUtils that provides five primary methods for live trading operations. Unlike backtesting which iterates through predefined timeframes, live trading runs an infinite loop with real-time timestamps and persists state for crash recovery.
| Method | Return Type | Purpose |
|---|---|---|
run(symbol, context) |
AsyncGenerator<IStrategyTickResultOpened | IStrategyTickResultClosed> |
Yields opened and closed signals in real-time |
background(symbol, context) |
() => void (cancellation closure) |
Runs live trading silently for side effects only |
getData(symbol, strategyName) |
Promise<LiveStatistics> |
Retrieves accumulated statistics from all live events |
getReport(symbol, strategyName) |
Promise<string> |
Generates markdown report with performance metrics |
dump(strategyName, path?) |
Promise<void> |
Saves markdown report to disk |
Live trading executes an infinite polling loop where each iteration calls tick() with the current timestamp. The loop sleeps for TICK_TTL (61 seconds by default) between iterations to prevent excessive API calls. Only opened and closed signals are yielded to the consumer; idle, active, and scheduled states trigger sleep without yielding.
Executes live trading with real-time signal streaming. Returns an infinite async generator that yields IStrategyTickResultOpened when positions open and IStrategyTickResultClosed when positions close with PNL data.
Live.run(
symbol: string,
context: {
strategyName: string;
exchangeName: string;
}
): AsyncGenerator<IStrategyTickResultOpened | IStrategyTickResultClosed>
Parameters:
symbol - Trading pair symbol (e.g., "BTCUSDT")context.strategyName - Registered strategy name from addStrategy()context.exchangeName - Registered exchange name from addExchange()Key Behaviors:
LiveMarkdownService and ScheduleMarkdownService for the symbol-strategy pair on start src/classes/Live.ts:68-70StrategyGlobalService cache to force re-initialization src/classes/Live.ts:73-74RiskGlobalService cache if risk profile exists src/classes/Live.ts:76-81Runs live trading silently without yielding results. Consumes all signals internally for side effects only (callbacks, persistence, logging). Returns a cancellation closure that can be called to gracefully stop execution after the current position closes.
Live.background(
symbol: string,
context: {
strategyName: string;
exchangeName: string;
}
): () => void
Cancellation Behavior:
StrategyGlobalService.stop() to prevent new signals src/classes/Live.ts:140doneLiveSubject src/classes/Live.ts:141-156doneLiveSubject with context metadata when complete src/classes/Live.ts:127-133Error Handling:
exitEmitter for fatal error handling src/classes/Live.ts:136-138Retrieves aggregated statistics from all live trading events for a symbol-strategy pair. Returns data accumulated by LiveMarkdownService including Sharpe ratio, win rate, PNL, and other performance metrics.
Live.getData(
symbol: string,
strategyName: StrategyName
): Promise<LiveStatistics>
Returns: LiveStatistics object containing:
Generates markdown-formatted report with all live trading events, statistics, and signal details for a symbol-strategy pair.
Live.getReport(
symbol: string,
strategyName: StrategyName
): Promise<string>
Returns: Markdown string containing:
Saves markdown report to disk at specified path. Defaults to ./dump/live/{strategyName}.md if path not provided.
Live.dump(
strategyName: StrategyName,
path?: string
): Promise<void>
Parameters:
strategyName - Strategy name (used as filename)path - Optional directory path (default: "./dump/live")Live trading persists critical state at each lifecycle transition to enable crash recovery. When the process restarts, ClientStrategy.waitForInit() blocks until persisted state is loaded from disk. If an active signal exists, monitoring of TP/SL/timeout conditions resumes seamlessly.
Persistence Points:
priceOpen ≠ currentPrice, enabling recovery of pending limit ordersAtomic Operations:
Each persistence adapter implements IPersistBase interface with atomic writeValue() operations, ensuring consistency during crashes. Default implementation uses file-based storage with JSON serialization.
| Aspect | Live Trading | Backtesting |
|---|---|---|
| Execution Model | Infinite while(true) loop |
Finite iteration through timeframes |
| Time Progression | Real-time new Date() |
Historical date array |
| Completion | Never completes naturally | Completes when last timeframe processed |
| Context Parameters | strategyName, exchangeName |
strategyName, exchangeName, frameName |
| Signal Evaluation | tick() with current timestamp |
backtest() with candle array |
| State Persistence | Required for crash recovery | Not used (deterministic replay) |
| Sleep Interval | TICK_TTL (61 seconds) between ticks |
No sleep (fast-forward through history) |
| Signal Yielding | Only opened and closed |
Only closed |
| Service Initialization | waitForInit() loads persisted state |
No initialization delay |
| Signal Emitters | signalLiveEmitter, signalEmitter |
signalBacktestEmitter, signalEmitter |
| Completion Event | doneLiveSubject |
doneBacktestSubject |
The Live API follows a multi-tier service architecture where each layer adds specific functionality:
while(true) and sleep(TICK_TTL)symbol:strategyName src/lib/services/connection/StrategyConnectionService.ts:78-98import { Live } from "backtest-kit";
// Infinite generator - use Ctrl+C to stop
for await (const result of Live.run("BTCUSDT", {
strategyName: "my-strategy",
exchangeName: "binance"
})) {
if (result.action === "opened") {
console.log("Position opened:", result.signal);
} else if (result.action === "closed") {
console.log("Position closed:", result.pnl.pnlPercentage);
}
}
import { Live } from "backtest-kit";
// Run in background, get cancellation closure
const cancel = Live.background("BTCUSDT", {
strategyName: "my-strategy",
exchangeName: "binance"
});
// Later: gracefully stop after current position closes
setTimeout(() => {
cancel();
console.log("Shutdown requested");
}, 60000 * 60); // 1 hour
import { Live } from "backtest-kit";
// Get statistics object
const stats = await Live.getData("BTCUSDT", "my-strategy");
console.log("Sharpe Ratio:", stats.sharpeRatio);
console.log("Win Rate:", stats.winRate);
// Get markdown report
const markdown = await Live.getReport("BTCUSDT", "my-strategy");
console.log(markdown);
// Save to disk
await Live.dump("my-strategy", "./reports");
Live trading uses two context services to propagate parameters implicitly through the call stack:
MethodContextService:
strategyName, exchangeNameLiveLogicPublicService when delegating to LiveLogicPrivateServiceStrategyGlobalService.tick() to determine which strategy to executeExecutionContextService:
symbol, when (timestamp), backtest (false for live)StrategyGlobalService.tick() using ExecutionContextService.runInContext()ClientStrategy to get current symbol and timestamp for signal evaluationThis architecture eliminates the need to pass these parameters through every function call in the service chain.