container lifecycle management

This commit is contained in:
2026-03-12 15:13:38 -04:00
parent e99ef5d2dd
commit b9cc397e05
61 changed files with 6880 additions and 31 deletions

View File

@@ -0,0 +1,253 @@
# LangGraph Workflows for Trading
Complex, stateful workflows built with LangGraph for trading-specific tasks.
## Overview
LangGraph provides:
- **Stateful execution**: Workflow state persists across failures
- **Conditional branching**: Route based on market conditions, backtest results, etc.
- **Human-in-the-loop**: Pause for user approval before executing trades
- **Loops & retries**: Backtest with different parameters, retry failed operations
- **Multi-agent**: Different LLMs for different tasks (analysis, risk, execution)
## Workflows
### Strategy Analysis (`strategy-analysis.ts`)
Multi-step pipeline for analyzing trading strategies:
```typescript
import { buildStrategyAnalysisWorkflow } from './workflows/strategy-analysis.js';
const workflow = buildStrategyAnalysisWorkflow(model, logger, mcpBacktestFn);
const result = await workflow.invoke({
strategyCode: userStrategy,
ticker: 'BTC/USDT',
timeframe: '1h',
});
console.log(result.recommendation); // Go/no-go decision
```
**Steps:**
1. **Code Review** - LLM analyzes strategy code for bugs, logic errors
2. **Backtest** - Runs backtest via user's MCP server
3. **Risk Assessment** - LLM evaluates results (drawdown, Sharpe, etc.)
4. **Human Approval** - Pauses for user review
5. **Recommendation** - Final go/no-go decision
**Benefits:**
- Stateful: Can resume if server restarts
- Human-in-the-loop: User must approve before deployment
- Multi-step reasoning: Each step builds on previous
---
## Future Workflows
### Market Scanner
Scan multiple tickers for trading opportunities:
```typescript
const scanner = buildMarketScannerWorkflow(model, logger);
const result = await scanner.invoke({
tickers: ['BTC/USDT', 'ETH/USDT', 'SOL/USDT'],
strategies: ['momentum', 'mean_reversion'],
timeframe: '1h',
});
// Returns ranked opportunities
```
**Steps:**
1. **Fetch Data** - Get OHLC for all tickers
2. **Apply Strategies** - Run each strategy on each ticker (parallel)
3. **Rank Signals** - Score by confidence, risk/reward
4. **Filter** - Apply user's risk limits
5. **Return Top N** - Best opportunities
---
### Portfolio Optimization
Optimize position sizing across multiple strategies:
```typescript
const optimizer = buildPortfolioOptimizerWorkflow(model, logger);
const result = await optimizer.invoke({
strategies: [strategy1, strategy2, strategy3],
totalCapital: 100000,
maxRiskPerTrade: 0.02,
});
// Returns optimal allocation
```
**Steps:**
1. **Backtest All** - Run backtests for each strategy
2. **Correlation Analysis** - Check strategy correlation
3. **Monte Carlo** - Simulate portfolio performance
4. **Optimize** - Find optimal weights (Sharpe maximization)
5. **Risk Check** - Validate against user limits
---
### Trade Execution Monitor
Monitor trade execution and adapt to market conditions:
```typescript
const monitor = buildTradeExecutionWorkflow(model, logger, exchange);
const result = await monitor.invoke({
tradeId: 'xyz',
targetPrice: 45000,
maxSlippage: 0.001,
timeLimit: 60, // seconds
});
```
**Steps:**
1. **Place Order** - Submit order to exchange
2. **Monitor Fill** - Check fill status every second
3. **Adapt** - If not filling, adjust price (within slippage)
4. **Retry Logic** - If rejected, retry with backoff
5. **Timeout** - Cancel if time limit exceeded
6. **Report** - Final execution report
---
## Using Workflows in Gateway
### Simple Chat vs Complex Workflow
```typescript
// gateway/src/orchestrator.ts
export class MessageOrchestrator {
async handleMessage(msg: InboundMessage) {
// Route based on complexity
if (this.isSimpleQuery(msg)) {
// Use agent harness for streaming chat
return this.harness.streamMessage(msg);
}
if (this.isWorkflowRequest(msg)) {
// Use LangGraph for complex analysis
return this.executeWorkflow(msg);
}
}
async executeWorkflow(msg: InboundMessage) {
const { type, params } = this.parseWorkflowRequest(msg);
switch (type) {
case 'analyze_strategy':
const workflow = buildStrategyAnalysisWorkflow(...);
return await workflow.invoke(params);
case 'scan_market':
const scanner = buildMarketScannerWorkflow(...);
return await scanner.invoke(params);
// ... more workflows
}
}
}
```
---
## Benefits for Trading
### vs Simple LLM Calls
| Scenario | Simple LLM | LangGraph Workflow |
|----------|-----------|-------------------|
| "What's the RSI?" | ✅ Fast, streaming | ❌ Overkill |
| "Analyze this strategy" | ❌ Limited context | ✅ Multi-step analysis |
| "Backtest 10 param combos" | ❌ No loops | ✅ Conditional loops |
| "Execute if approved" | ❌ No state | ✅ Human-in-the-loop |
| Server crashes mid-analysis | ❌ Lost progress | ✅ Resume from checkpoint |
### When to Use Workflows
**Use LangGraph when:**
- Multi-step analysis (backtest → risk → approval)
- Conditional logic (if bullish → momentum, else → mean-reversion)
- Human approval required (pause workflow)
- Loops needed (try different parameters)
- Long-running (can survive restarts)
**Use Agent Harness when:**
- Simple Q&A ("What is RSI?")
- Fast response needed (streaming chat)
- Single tool call ("Get my watchlist")
- Real-time interaction (Telegram, WebSocket)
---
## Implementation Notes
### State Persistence
LangGraph can persist state to database:
```typescript
import { MemorySaver } from '@langchain/langgraph';
const checkpointer = new MemorySaver();
const workflow = graph.compile({ checkpointer });
// Resume from checkpoint
const result = await workflow.invoke(input, {
configurable: { thread_id: 'user-123-strategy-analysis' }
});
```
### Human-in-the-Loop
Pause workflow for user input:
```typescript
const workflow = graph
.addNode('human_approval', humanApprovalNode)
.interrupt('human_approval'); // Pauses here
// User reviews in UI
const approved = await getUserApproval(workflowId);
// Resume workflow
await workflow.resume(state, { approved });
```
### Multi-Agent
Use different models for different tasks:
```typescript
const analysisModel = new ChatAnthropic({ model: 'claude-3-opus' }); // Smart
const codeModel = new ChatOpenAI({ model: 'gpt-4o' }); // Good at code
const cheapModel = new ChatOpenAI({ model: 'gpt-4o-mini' }); // Fast
const workflow = graph
.addNode('analyze', (state) => analysisModel.invoke(...))
.addNode('code_review', (state) => codeModel.invoke(...))
.addNode('summarize', (state) => cheapModel.invoke(...));
```
---
## Next Steps
1. Implement remaining workflows (scanner, optimizer, execution)
2. Add state persistence (PostgreSQL checkpointer)
3. Integrate human-in-the-loop with WebSocket
4. Add workflow monitoring dashboard
5. Performance optimization (parallel execution)

View File

@@ -0,0 +1,162 @@
import { StateGraph, Annotation } from '@langchain/langgraph';
import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
import { HumanMessage, SystemMessage } from '@langchain/core/messages';
import type { FastifyBaseLogger } from 'fastify';
/**
* State for strategy analysis workflow
*/
const StrategyAnalysisState = Annotation.Root({
strategyCode: Annotation<string>(),
ticker: Annotation<string>(),
timeframe: Annotation<string>(),
// Analysis steps
codeReview: Annotation<string | null>({
default: () => null,
}),
backtestResults: Annotation<Record<string, unknown> | null>({
default: () => null,
}),
riskAssessment: Annotation<string | null>({
default: () => null,
}),
humanApproved: Annotation<boolean>({
default: () => false,
}),
// Final output
recommendation: Annotation<string | null>({
default: () => null,
}),
});
type StrategyAnalysisStateType = typeof StrategyAnalysisState.State;
/**
* Build strategy analysis workflow using LangGraph
*
* Workflow steps:
* 1. Code review (LLM analyzes strategy code)
* 2. Backtest (calls user's MCP backtest tool)
* 3. Risk assessment (LLM evaluates results)
* 4. Human approval (pause for user review)
* 5. Final recommendation
*/
export function buildStrategyAnalysisWorkflow(
model: BaseChatModel,
logger: FastifyBaseLogger,
mcpBacktestFn: (strategy: string, ticker: string, timeframe: string) => Promise<Record<string, unknown>>
) {
// Node: Code Review
const codeReviewNode = async (state: StrategyAnalysisStateType) => {
logger.info('Strategy workflow: Code review');
const systemPrompt = `You are an expert trading strategy analyst.
Review the following strategy code for potential issues, bugs, or improvements.
Focus on: logic errors, edge cases, performance, and trading best practices.`;
const response = await model.invoke([
new SystemMessage(systemPrompt),
new HumanMessage(`Review this strategy:\n\n${state.strategyCode}`),
]);
return {
codeReview: response.content as string,
};
};
// Node: Backtest
const backtestNode = async (state: StrategyAnalysisStateType) => {
logger.info('Strategy workflow: Running backtest');
const results = await mcpBacktestFn(state.strategyCode, state.ticker, state.timeframe);
return {
backtestResults: results,
};
};
// Node: Risk Assessment
const riskAssessmentNode = async (state: StrategyAnalysisStateType) => {
logger.info('Strategy workflow: Risk assessment');
const systemPrompt = `You are a risk management expert for trading strategies.
Analyze the backtest results and provide a risk assessment.
Focus on: drawdown, win rate, Sharpe ratio, position sizing, and risk of ruin.`;
const response = await model.invoke([
new SystemMessage(systemPrompt),
new HumanMessage(
`Code review: ${state.codeReview}\n\nBacktest results: ${JSON.stringify(state.backtestResults, null, 2)}\n\nProvide risk assessment:`
),
]);
return {
riskAssessment: response.content as string,
};
};
// Node: Human Approval (placeholder - would integrate with UI)
const humanApprovalNode = async (state: StrategyAnalysisStateType) => {
logger.info('Strategy workflow: Awaiting human approval');
// In real implementation, this would pause and wait for user input
// For now, auto-approve
return {
humanApproved: true,
};
};
// Node: Final Recommendation
const recommendationNode = async (state: StrategyAnalysisStateType) => {
logger.info('Strategy workflow: Generating recommendation');
const systemPrompt = `Provide a final recommendation on whether to deploy this trading strategy.
Summarize the code review, backtest results, and risk assessment.
Give clear go/no-go decision with reasoning.`;
const response = await model.invoke([
new SystemMessage(systemPrompt),
new HumanMessage(
`Code review: ${state.codeReview}\n\nBacktest: ${JSON.stringify(state.backtestResults)}\n\nRisk: ${state.riskAssessment}\n\nApproved: ${state.humanApproved}\n\nYour recommendation:`
),
]);
return {
recommendation: response.content as string,
};
};
// Build graph
const workflow = new StateGraph(StrategyAnalysisState)
.addNode('code_review', codeReviewNode)
.addNode('backtest', backtestNode)
.addNode('risk_assessment', riskAssessmentNode)
.addNode('human_approval', humanApprovalNode)
.addNode('recommendation', recommendationNode)
.addEdge('__start__', 'code_review')
.addEdge('code_review', 'backtest')
.addEdge('backtest', 'risk_assessment')
.addEdge('risk_assessment', 'human_approval')
.addConditionalEdges('human_approval', (state) => {
return state.humanApproved ? 'recommendation' : '__end__';
})
.addEdge('recommendation', '__end__');
return workflow.compile();
}
/**
* Example usage:
*
* const workflow = buildStrategyAnalysisWorkflow(model, logger, mcpBacktestFn);
*
* const result = await workflow.invoke({
* strategyCode: "strategy code here",
* ticker: "BTC/USDT",
* timeframe: "1h",
* });
*
* console.log(result.recommendation);
*/