OS Trading Engine
Technical Documentation
Architecture
Data Flow

Data Flow

This page documents how data flows through the Nexgent trading engine, from signal creation to trade execution to real-time updates.

Signal Processing Flow

When a trading signal is created, it triggers a cascade of operations across multiple services.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Signal Source  β”‚  (API, Webhook, Manual)
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  POST /signals  β”‚  Create signal in database
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Event Emitter  β”‚  Emit 'signal_created' event
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚Signal Processor β”‚  Listen for signal events
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Agent Eligibilityβ”‚  Check which agents can trade
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό (parallel for each eligible agent)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚Trading Executor β”‚  Execute purchase for agent
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Position Createdβ”‚  Emit 'position_created' event
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   WebSocket     β”‚  Broadcast to connected clients
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Agent Eligibility Check

Before executing a trade, the system validates:

  1. Agent Active - Agent exists and is not disabled
  2. Automated Trading Enabled - For the current trading mode (simulation/live)
  3. Wallet Available - Agent has a wallet assigned for the trading mode
  4. Sufficient Balance - Wallet has enough SOL for position size
  5. No Existing Position - No open position in this token
  6. Signal Not Already Processed - Idempotency check

Eligibility checks are performed against Redis cache first for speed, falling back to database only when cache misses occur.


Trade Execution Flow

The Trading Executor orchestrates the complete trade lifecycle.

Purchase Flow

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      Trading Executor                            β”‚
β”‚                                                                  β”‚
β”‚  1. Validate Trade                                               β”‚
β”‚     β”œβ”€β”€ Check agent config                                       β”‚
β”‚     β”œβ”€β”€ Verify wallet balance                                    β”‚
β”‚     └── Calculate position size                                  β”‚
β”‚                                                                  β”‚
β”‚  2. Get Swap Quote (Jupiter API)                                 β”‚
β”‚     β”œβ”€β”€ Input: SOL amount                                        β”‚
β”‚     β”œβ”€β”€ Output: Token amount                                     β”‚
β”‚     └── Check price impact                                       β”‚
β”‚                                                                  β”‚
β”‚  3. Execute Swap                                                 β”‚
β”‚     β”œβ”€β”€ Simulation: Use quote values                             β”‚
β”‚     └── Live: Sign and submit transaction                        β”‚
β”‚                                                                  β”‚
β”‚  4. Database Transaction (atomic)                                β”‚
β”‚     β”œβ”€β”€ Create transaction record                                β”‚
β”‚     β”œβ”€β”€ Update balances (SOL ↓, Token ↑)                         β”‚
β”‚     └── Create position record                                   β”‚
β”‚                                                                  β”‚
β”‚  5. Update Redis Cache                                           β”‚
β”‚     β”œβ”€β”€ Update balance cache                                     β”‚
β”‚     └── Update position cache                                    β”‚
β”‚                                                                  β”‚
β”‚  6. Initialize Stop Loss                                         β”‚
β”‚     └── Set initial stop loss percentage                         β”‚
β”‚                                                                  β”‚
β”‚  7. Emit Events                                                  β”‚
β”‚     └── 'position_created' β†’ WebSocket broadcast                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Sale Flow (Stop Loss / Manual)

1. Load position from cache/database
2. Validate position belongs to agent
3. Get swap quote (Token β†’ SOL)
4. Execute swap
5. Database transaction (atomic)
   β”œβ”€β”€ Create sale transaction
   β”œβ”€β”€ Update balances (Token ↓, SOL ↑)
   └── Delete position
6. Queue historical swap record (async)
7. Update Redis cache
8. Emit 'position_closed' event

Price Update Flow

The Price Update Manager continuously monitors prices and triggers automated actions.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Price Update Manager                           β”‚
β”‚                                                                   β”‚
β”‚  Every 1.5 seconds:                                               β”‚
β”‚                                                                   β”‚
β”‚  1. Get Tracked Tokens                                            β”‚
β”‚     └── All tokens with active positions                          β”‚
β”‚                                                                   β”‚
β”‚  2. Fetch Prices (DexScreener/Jupiter)                            β”‚
β”‚     └── Batch request for all tracked tokens                      β”‚
β”‚                                                                   β”‚
β”‚  3. For Each Price Update:                                        β”‚
β”‚     β”œβ”€β”€ Update local cache                                        β”‚
β”‚     β”œβ”€β”€ Update Redis cache                                        β”‚
β”‚     β”‚                                                             β”‚
β”‚     β”œβ”€β”€ Evaluate Stop Loss                                        β”‚
β”‚     β”‚   β”œβ”€β”€ Check if price dropped below stop loss level          β”‚
β”‚     β”‚   β”œβ”€β”€ If trailing stop enabled, check from peak price       β”‚
β”‚     β”‚   └── Trigger sale if conditions met                        β”‚
β”‚     β”‚                                                             β”‚
β”‚     β”œβ”€β”€ Evaluate Stale Trade (if stop loss didn't trigger)        β”‚
β”‚     β”‚   β”œβ”€β”€ Check position age > min hold time                    β”‚
β”‚     β”‚   β”œβ”€β”€ Check profit in target range                          β”‚
β”‚     β”‚   └── Trigger sale if conditions met                        β”‚
β”‚     β”‚                                                             β”‚
β”‚     β”œβ”€β”€ Evaluate DCA (if no sale triggered)                       β”‚
β”‚     β”‚   β”œβ”€β”€ Check if price dropped to DCA level                   β”‚
β”‚     β”‚   β”œβ”€β”€ Check if DCA attempts remaining                       β”‚
β”‚     β”‚   └── Trigger DCA buy if conditions met                     β”‚
β”‚     β”‚                                                             β”‚
β”‚     └── Collect WebSocket Updates                                 β”‚
β”‚                                                                   β”‚
β”‚  4. Batch Broadcast Price Updates                                 β”‚
β”‚     └── Send batched updates per connected agent                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
πŸ’‘

Stop loss evaluation happens on every price update (every 1.5s). The trailing stop loss tracks peak price and tightens as profit increases.


WebSocket Data Flow

Real-time updates flow from backend to frontend via WebSocket.

Connection Flow

Frontend                                Backend
   β”‚                                       β”‚
   β”‚  Connect with JWT + agentId           β”‚
   β”‚ ────────────────────────────────────► β”‚
   β”‚                                       β”‚ Verify JWT
   β”‚                                       β”‚ Validate agent ownership
   β”‚                                       β”‚
   β”‚  'connected' message                  β”‚
   β”‚ ◄──────────────────────────────────── β”‚
   β”‚                                       β”‚
   β”‚  'initial_data' (positions)           β”‚
   β”‚ ◄──────────────────────────────────── β”‚
   β”‚                                       β”‚
   β”‚  Periodic 'ping'                      β”‚
   β”‚ ◄──────────────────────────────────── β”‚
   β”‚  'pong' response                      β”‚
   β”‚ ────────────────────────────────────► β”‚
   β”‚                                       β”‚

Message Types

Message TypeDirectionPayload
connectedServer β†’ ClientAgent ID, timestamp
initial_dataServer β†’ ClientArray of enriched positions
position_updateServer β†’ ClientPosition created/updated/closed
price_update_batchServer β†’ ClientArray of token prices
pingServer β†’ ClientTimestamp
pongClient β†’ ServerTimestamp
errorServer β†’ ClientError message

Frontend State Updates

WebSocket Message
       β”‚
       β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  useWebSocket   β”‚  React hook
β”‚     Hook        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β”œβ”€β”€β”€ initial_data ──────► Set positions state
         β”‚
         β”œβ”€β”€β”€ position_update ───► Update/add/remove position
         β”‚                         Invalidate React Query cache
         β”‚
         └─── price_update_batch ─► Batch queue updates
                                    Apply via requestAnimationFrame

Caching Strategy

Write-Through Pattern

All writes go through both database and cache atomically.

Write Request
     β”‚
     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ DB Transaction  β”‚
β”‚   (Prisma)      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚ commit
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Redis Update   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ WebSocket Event β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Cache Key Patterns

Key PatternDataTTL
balance:{agentId}:{wallet}:{token}Balance recordNone (write-through)
position:{agentId}:{wallet}:{token}Position recordNone (write-through)
price:{tokenAddress}Price data60s
agent:{agentId}Agent config300s
idempotency:{key}Deduplication60s

Database Transactions

Critical operations use atomic database transactions.

Purchase Transaction

await prisma.$transaction(async (tx) => {
  // 1. Create transaction record
  await tx.agentTransaction.create({ ... });
  
  // 2. Update balances
  await tx.agentBalance.upsert({ ... }); // SOL decrease
  await tx.agentBalance.upsert({ ... }); // Token increase
  
  // 3. Create position
  await tx.agentPosition.create({ ... });
});
// After commit: Update Redis, emit events

Sale Transaction

await prisma.$transaction(async (tx) => {
  // 1. Create sale transaction
  await tx.agentTransaction.create({ ... });
  
  // 2. Update balances
  await tx.agentBalance.update({ ... }); // Token decrease
  await tx.agentBalance.update({ ... }); // SOL increase
  
  // 3. Delete position
  await tx.agentPosition.delete({ ... });
});
// After commit: Queue historical swap, update Redis, emit events

Event Flow Summary

EventEmitterListeners
signal_createdSignal APISignal Processor
position_createdTrading ExecutorWebSocket Server, Price Update Manager
position_updatedPosition ServiceWebSocket Server
position_closedTrading ExecutorWebSocket Server, Price Update Manager