Overview
NeuraTrade’s autonomous trading system uses a quest engine to schedule and execute trading strategies without human intervention. The system supports routine quests (scheduled), triggered quests (event-driven), and goal-based quests (milestone-driven).
Quest Types
Time-triggered quests that run on a fixed schedule (micro/hourly/daily/weekly).services/backend-api/internal/services/quest_engine.go:22-27
const (
QuestTypeRoutine QuestType = "routine" // Time-triggered
QuestTypeTriggered QuestType = "triggered" // Event-driven
QuestTypeGoal QuestType = "goal" // Milestone-driven
QuestTypeArbitrage QuestType = "arbitrage" // Arbitrage execution
)
Event-driven quests activated by market conditions (volatility spikes, arbitrage opportunities, risk events).Triggered quests are created dynamically when specific market conditions are detected.
Milestone-driven quests that track progress toward a financial target (fund growth, win rate, PnL targets).
Quest Engine Architecture
Core Components
services/backend-api/internal/services/quest_engine.go:141-168
type QuestEngine struct {
mu sync . RWMutex
quests map [ string ] * Quest
executing map [ string ] bool
executionStarts map [ string ] time . Time
executionStage map [ string ] string
autonomousState map [ string ] * AutonomousState
definitions map [ string ] * QuestDefinition
handlers map [ QuestType ] QuestHandler
store QuestStore
redis * redis . Client // Distributed locks
runtimeBudget questRuntimeBudget
riskLockActive bool
notificationService * NotificationService
}
Quest Lifecycle
Creation
Quest created from a definition with a unique ID, target count, and metadata.
Scheduling
Quest enters the scheduler queue based on its cadence (micro/hourly/daily/weekly).
Lock Acquisition
Before execution, a distributed Redis lock is acquired to prevent duplicate runs across instances.
Handler Execution
The quest handler executes the trading logic (market scan, signal generation, order placement).
Persistence
Quest progress, checkpoints, and status are persisted to the database.
Completion
Quest marked as completed (one-time) or re-scheduled (routine).
Default Quest Definitions
The quest engine registers several built-in quests on startup:
ID : market_scan
Cadence : Micro (every 1-5 minutes)
Purpose : Scan all exchanges for price discrepancies and arbitrage opportunitiesservices/backend-api/internal/services/quest_engine.go:321-328
e . RegisterDefinition ( & QuestDefinition {
ID : "market_scan" ,
Name : "Market Scanner" ,
Description : "Scan markets for arbitrage opportunities" ,
Type : QuestTypeRoutine ,
Cadence : CadenceMicro ,
Prompt : "Scan all configured exchanges for price discrepancies" ,
})
ID : scalping_execution
Cadence : Micro (every 1-5 minutes)
Purpose : Execute scalping trades based on skill parameters and market conditionsservices/backend-api/internal/services/quest_engine.go:371-378
e . RegisterDefinition ( & QuestDefinition {
ID : "scalping_execution" ,
Name : "Scalping Executor" ,
Description : "Execute scalping trades based on skill parameters" ,
Type : QuestTypeRoutine ,
Cadence : CadenceMicro ,
Prompt : "Scan for scalping opportunities and execute trades" ,
})
Scalping quests operate in live trading mode by default (dry_run=false). Ensure risk limits are configured.
ID : funding_rate_scan
Cadence : Micro
Purpose : Check funding rates across futures exchanges for arbitrage opportunities
ID : portfolio_health
Cadence : Hourly
Purpose : Verify portfolio balances, exposure limits, and position health
ID : daily_report
Cadence : Daily
Purpose : Generate comprehensive daily report including PnL, win rate, and strategy performance
Agent Execution Loop
When a quest runs, it triggers the multi-agent execution loop that coordinates Analyst, Trader, and Risk Manager agents.
Execution Pipeline
services/backend-api/internal/services/agent_execution_loop.go:254-382
func ( l * AgentExecutionLoop ) Execute (
ctx context . Context ,
symbol string ,
marketContext MarketContext ,
portfolio PortfolioState ,
) ( * ExecutionLoopResult , error ) {
// Step 1: Run AnalystAgent analysis
analysis , err := l . runAnalysis ( ctx , symbol , marketContext )
// Step 2: Run LLM with tool calling (optional)
if l . llmClient != nil && l . config . EnableToolCalls {
toolCalls , toolResults , _ := l . runLLMWithTools ( ctx , symbol , analysis , marketContext )
}
// Step 3: Generate trading decision using TraderAgent
tradingDecision , err := l . traderAgent . MakeDecision ( ctx , marketContext , portfolio )
// Step 4: Run risk assessment
if l . config . RequireRiskApproval {
riskAssessment , err := l . riskManager . AssessTradingRisk ( ctx , symbol , side , riskSignals )
// Block or reduce position based on risk level
switch riskAssessment . Action {
case risk . RiskActionBlock , risk . RiskActionEmergency :
result . Decision = ExecutionDecisionReject
return result , nil
case risk . RiskActionReduce :
tradingDecision . SizePercent = adjustedSize
}
}
// Step 5: Approve execution if confidence threshold met
if result . Confidence >= l . config . MinConfidence {
result . Decision = ExecutionDecisionApprove
}
// Step 6: Execute order if auto-execute enabled
if l . config . AutoExecute && l . orderExecutor != nil {
l . orderExecutor . ExecuteOrder ( ctx , tradingDecision )
}
return result , nil
}
Configuration
services/backend-api/internal/services/agent_execution_loop.go:38-52
type AgentExecutionLoopConfig struct {
MaxIterations int // Max LLM iterations per cycle
Timeout time . Duration // Max time for execution cycle
RequireRiskApproval bool // Require risk manager approval
MinConfidence float64 // Min confidence threshold (0.0-1.0)
EnableToolCalls bool // Enable LLM tool calling
AutoExecute bool // Auto-execute approved orders
}
// Default configuration
func DefaultAgentExecutionLoopConfig () AgentExecutionLoopConfig {
return AgentExecutionLoopConfig {
MaxIterations : 5 ,
Timeout : 60 * time . Second ,
RequireRiskApproval : true ,
MinConfidence : 0.7 ,
EnableToolCalls : true ,
AutoExecute : false , // Manual approval by default
}
}
Autonomous Mode Lifecycle
Starting Autonomous Mode
services/backend-api/internal/services/quest_engine.go:1156-1210
func ( e * QuestEngine ) BeginAutonomous ( chatID string ) ( * AutonomousState , error ) {
e . mu . Lock ()
defer e . mu . Unlock ()
// Pause existing active quests for this chat
for _ , q := range e . quests {
if q . Status == QuestStatusActive && q . Metadata [ "chat_id" ] == chatID {
q . Status = QuestStatusPaused
}
}
state := & AutonomousState {
ChatID : chatID ,
IsActive : true ,
StartedAt : time . Now (),
}
// Create default quests (scalping-first mode)
defaultQuests := [] string { "scalping_execution" }
for _ , defID := range defaultQuests {
quest , _ := e . createQuestInternal ( defID , chatID )
quest . Status = QuestStatusActive
quest . Metadata [ "dry_run" ] = "false" // LIVE TRADING
state . ActiveQuests = append ( state . ActiveQuests , quest . ID )
}
return state , nil
}
Live Trading Warning : Autonomous mode defaults to dry_run=false for live trading. Always verify risk limits before activation.
Cadence Modes
The quest scheduler adapts its polling frequency based on system state:
Normal
Active Risk
Degraded
Idle
Risk Lock
60 seconds - Standard polling interval when no quests are executing
25 seconds - Faster polling when quests are currently executing
90 seconds - Slower polling when runtime failures are detected
120 seconds - Slowest polling when no active quests exist
25 seconds - Monitoring mode when risk lock is active (no new entries allowed)
services/backend-api/internal/services/quest_engine.go:596-631
func ( e * QuestEngine ) determineCadenceModeLocked () string {
if e . isRiskLockEnabledLocked () {
return "risk_lock"
}
activeQuests := 0
for _ , quest := range e . quests {
if quest . Status == QuestStatusActive {
activeQuests ++
}
}
if activeQuests == 0 {
return "idle"
}
if len ( e . executing ) > 0 {
return "active_risk"
}
return "normal"
}
Distributed Coordination
Quests use Redis distributed locks to ensure only one instance executes a quest at a time:
services/backend-api/internal/services/quest_engine.go:1099-1109
func ( e * QuestEngine ) acquireLock ( ctx context . Context , key string , ttl time . Duration ) bool {
if e . redis == nil {
return true // No Redis, allow execution
}
ok , err := e . redis . SetNX ( ctx , key , "locked" , ttl ). Result ()
if err != nil {
log . Printf ( "Failed to acquire lock %s : %v " , key , err )
return false
}
return ok
}
Lock TTL Calculation
Lock TTL is dynamically calculated based on execution budget:
Lock TTL = Execution Timeout + Lock Tail Buffer
= (Stale Timeout + 20s) + 35s
= (3min + 20s) + 35s
= 4min 55s
Paper vs Live Execution
Paper Trading Mode
Paper trading simulates order execution without placing real orders. Useful for testing strategies and validating risk limits.
// Quest metadata controls execution mode
quest . Metadata [ "dry_run" ] = "true" // Paper trading
quest . Metadata [ "paper_trading" ] = "true"
Live Trading Mode
Risk Warning : Live mode executes real orders on exchanges. Ensure:
API keys have correct permissions
Risk limits are configured
Sufficient balance exists
Circuit breakers are active
// Live trading configuration
quest . Metadata [ "dry_run" ] = "false" // LIVE TRADING
quest . Metadata [ "paper_trading" ] = "false"
Telegram Bot Control
Control autonomous mode via Telegram commands:
/begin Start autonomous trading mode. Creates scalping quest and begins execution.
/pause Pause all active quests. Existing positions remain open.
/status View current autonomous state, active quests, and runtime diagnostics.
/doctor Run diagnostics on quest scheduler, risk gates, and AI provider chain.
Monitoring & Diagnostics
Runtime Diagnostics
services/backend-api/internal/services/quest_engine.go:1346-1389
func ( e * QuestEngine ) GetRuntimeDiagnostics () map [ string ] interface {} {
return map [ string ] interface {}{
"cadence_mode" : e . cadenceMode ,
"active_quests" : len ( e . quests ),
"executing_quests" : len ( e . executing ),
"risk_lock_active" : e . isRiskLockEnabledLocked (),
"risk_lock_source" : e . currentRiskLockSourceLocked (),
"execution_stage" : executionStage ,
"execution_last_progress_at" : executionLastProgress ,
"provider_chain_configured" : e . aiProviderChainConfigured ,
"provider_chain_usable" : e . aiProviderChainUsable ,
"watchdog_stale" : e . runtimeBudget . StaleTimeout ,
"execution_timeout" : e . runtimeBudget . ExecutionTimeout ,
"lock_ttl" : e . runtimeBudget . LockTTL ,
}
}
Execution Metrics
services/backend-api/internal/services/agent_execution_loop.go:95-109
type ExecutionLoopMetrics struct {
TotalCycles int64
ApprovedExecutions int64
RejectedExecutions int64
DeferredExecutions int64
EmergencyTriggers int64
TotalToolCalls int64
FailedToolCalls int64
AverageIterations float64
AverageExecutionTime float64 // milliseconds
AverageConfidence float64
DecisionsBySymbol map [ string ] int64
DecisionsByAction map [ string ] int64
}
Best Practices
Start with Paper Trading Always test new strategies in paper trading mode before going live.
Monitor Execution Stages Track execution stage progression. Stuck stages indicate network or lock issues.
Configure Risk Locks Set daily loss caps, consecutive loss limits, and max drawdown thresholds.
Review Quest Checkpoints Quest checkpoints store state between executions. Review for debugging.
AI Agents Learn about the multi-agent system powering quest execution
Risk Management Understand risk primitives that gate quest execution
Telegram Bot Control autonomous mode via Telegram commands