trading-bot-architecture
Design and build Solana trading bots - execution engine, position management, risk controls, and operational infrastructure. Use when building swap bots, arbitrage bots, or automated trading systems.
How do I install this agent skill?
npx skills add https://github.com/sanctifiedops/solana-skills --skill trading-bot-architectureIs this agent skill safe to install?
- Gen Agent Trust Hubpass
The skill provides an architectural blueprint and code templates for designing a Solana trading bot. No security vulnerabilities, malicious patterns, or prompt injections were found.
- Socketwarn
1 alert: gptSecurity
- Snykwarn
Risk: MEDIUM · 1 issue
- Runlayerwarn
1/1 file flagged
What does this agent skill do?
Trading Bot Architecture
Role framing: You are a trading systems architect building automated trading bots on Solana. Your goal is to design reliable, safe, and efficient trading systems with proper risk controls and operational monitoring.
Initial Assessment
- What type of trading: market making, arbitrage, trend following, sniping?
- Target assets: SOL pairs, memecoins, specific tokens?
- Capital allocation: how much per trade, total capital at risk?
- Latency requirements: milliseconds matter or seconds acceptable?
- Risk tolerance: max drawdown, position limits, loss limits?
- Infrastructure: where will bot run, what RPC access?
- Manual oversight: 24/7 autonomous or supervised?
Core Principles
- Never risk more than you can lose: Hard position limits, not just soft warnings.
- Fail safe, not fail open: On error, close positions or stop trading, don't continue blindly.
- Execution reliability > speed: A trade that lands beats a fast trade that fails.
- Log everything: Every decision, every order, every fill. Debug tomorrow's disaster today.
- Separate concerns: Price feeds, signals, execution, and risk are different systems.
- Test with real money carefully: Paper trading hides latency and slippage reality.
Workflow
1. System Architecture
┌─────────────────────────────────────────────────────────────┐
│ Trading Bot │
├──────────────┬──────────────┬──────────────┬────────────────┤
│ Data Feed │ Strategy │ Execution │ Risk │
│ Module │ Engine │ Engine │ Manager │
├──────────────┼──────────────┼──────────────┼────────────────┤
│ - Prices │ - Signals │ - Order mgmt │ - Position lim │
│ - Orderbook │ - Entry/exit │ - Jito/RPC │ - Loss limits │
│ - On-chain │ - Sizing │ - Retries │ - Drawdown │
│ - Socials │ - Filters │ - Status │ - Kill switch │
└──────────────┴──────────────┴──────────────┴────────────────┘
│ │ │ │
└───────────────┴──────────────┴──────────────┘
│
┌─────────┴─────────┐
│ Infrastructure │
├───────────────────┤
│ - RPC connections │
│ - Wallet mgmt │
│ - Logging │
│ - Alerting │
└───────────────────┘
2. Core Components
// Main bot structure
interface TradingBot {
// Configuration
config: BotConfig;
// Core modules
dataFeed: DataFeedModule;
strategy: StrategyEngine;
execution: ExecutionEngine;
risk: RiskManager;
// State
positions: Map<string, Position>;
openOrders: Map<string, Order>;
status: BotStatus;
// Lifecycle
start(): Promise<void>;
stop(): Promise<void>;
pause(): void;
resume(): void;
}
interface BotConfig {
// Trading parameters
tradingPairs: string[];
maxPositionSize: number; // Per token
maxTotalExposure: number; // Total USD
maxConcurrentPositions: number;
// Risk limits
maxLossPerTrade: number; // USD
maxDailyLoss: number; // USD
maxDrawdownPercent: number; // % of capital
// Execution
defaultSlippageBps: number;
maxSlippageBps: number;
priorityFeeMicroLamports: number;
useJito: boolean;
// Infrastructure
rpcEndpoints: string[];
wsEndpoints: string[];
jitoEndpoint?: string;
}
3. Data Feed Module
interface DataFeedModule {
// Price data
getPrice(mint: string): Promise<PriceData>;
subscribePrices(mints: string[], callback: PriceCallback): Subscription;
// On-chain data
getTokenAccount(mint: string, owner: string): Promise<TokenAccountData>;
getPoolState(poolAddress: string): Promise<PoolState>;
// Health
isHealthy(): boolean;
getLatency(): number;
}
class JupiterPriceFeed implements DataFeedModule {
private priceCache: Map<string, { price: number; timestamp: number }>;
private cacheTTL = 1000; // 1 second
async getPrice(mint: string): Promise<PriceData> {
// Check cache
const cached = this.priceCache.get(mint);
if (cached && Date.now() - cached.timestamp < this.cacheTTL) {
return { price: cached.price, source: 'cache' };
}
// Fetch from Jupiter
const response = await fetch(
`https://price.jup.ag/v6/price?ids=${mint}`
);
const data = await response.json();
// Update cache
this.priceCache.set(mint, {
price: data.data[mint].price,
timestamp: Date.now(),
});
return { price: data.data[mint].price, source: 'jupiter' };
}
}
4. Strategy Engine
interface StrategyEngine {
// Generate signals
evaluate(data: MarketData): Signal[];
// Position sizing
calculateSize(signal: Signal, risk: RiskState): number;
// Entry/exit logic
shouldEnter(signal: Signal): boolean;
shouldExit(position: Position, data: MarketData): boolean;
}
interface Signal {
type: 'LONG' | 'SHORT' | 'EXIT';
token: string;
confidence: number; // 0-1
reason: string;
metadata: any;
}
// Example: Simple momentum strategy
class MomentumStrategy implements StrategyEngine {
private readonly minConfidence = 0.6;
private readonly lookbackPeriod = 60; // seconds
evaluate(data: MarketData): Signal[] {
const signals: Signal[] = [];
for (const token of data.watchlist) {
const priceChange = this.calculatePriceChange(token, this.lookbackPeriod);
const volumeSpike = this.detectVolumeSpike(token);
if (priceChange > 5 && volumeSpike) {
signals.push({
type: 'LONG',
token,
confidence: Math.min(priceChange / 10, 1),
reason: `${priceChange.toFixed(1)}% gain with volume spike`,
metadata: { priceChange, volumeSpike },
});
}
}
return signals;
}
calculateSize(signal: Signal, risk: RiskState): number {
// Base size from config
let size = risk.maxPositionSize;
// Scale by confidence
size *= signal.confidence;
// Reduce if approaching limits
const utilizationRatio = risk.currentExposure / risk.maxExposure;
if (utilizationRatio > 0.8) {
size *= (1 - utilizationRatio);
}
return Math.floor(size);
}
}
5. Execution Engine
interface ExecutionEngine {
// Order management
submitOrder(order: Order): Promise<OrderResult>;
cancelOrder(orderId: string): Promise<boolean>;
getOrderStatus(orderId: string): Promise<OrderStatus>;
// Position management
openPosition(params: OpenPositionParams): Promise<Position>;
closePosition(positionId: string): Promise<CloseResult>;
}
class JupiterExecutionEngine implements ExecutionEngine {
private connection: Connection;
private wallet: Keypair;
async submitOrder(order: Order): Promise<OrderResult> {
const startTime = Date.now();
try {
// Get quote
const quote = await this.getQuote(order);
// Validate quote
if (quote.priceImpactPct > order.maxPriceImpact) {
return {
success: false,
error: 'Price impact too high',
priceImpact: quote.priceImpactPct,
};
}
// Get swap transaction
const swapTx = await this.getSwapTransaction(quote, order);
// Execute with retry
const result = await this.executeWithRetry(swapTx, order.maxRetries);
return {
success: result.success,
signature: result.signature,
executionTime: Date.now() - startTime,
fillPrice: this.calculateFillPrice(result),
slippage: this.calculateSlippage(quote, result),
};
} catch (error) {
return {
success: false,
error: error.message,
executionTime: Date.now() - startTime,
};
}
}
private async executeWithRetry(
swapTx: VersionedTransaction,
maxRetries: number
): Promise<ExecutionResult> {
let lastError: Error;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
// Increase priority fee on retry
const priorityFee = this.config.basePriorityFee * Math.pow(1.5, attempt - 1);
const signature = await this.sendTransaction(swapTx, priorityFee);
const confirmation = await this.confirmTransaction(signature);
if (confirmation.success) {
return { success: true, signature, attempts: attempt };
}
} catch (error) {
lastError = error;
// Don't retry on certain errors
if (this.isFatalError(error)) {
break;
}
await this.sleep(100 * attempt);
}
}
return { success: false, error: lastError, attempts: maxRetries };
}
}
6. Risk Manager
interface RiskManager {
// Pre-trade checks
canTrade(order: Order): RiskCheckResult;
// Position monitoring
checkPositions(): RiskAlert[];
// Kill switch
emergencyStop(reason: string): Promise<void>;
// State
getRiskState(): RiskState;
}
class DefaultRiskManager implements RiskManager {
private state: RiskState;
private alerts: RiskAlert[] = [];
canTrade(order: Order): RiskCheckResult {
const checks: RiskCheck[] = [];
// Check 1: Position size limit
checks.push({
name: 'positionSize',
passed: order.size <= this.config.maxPositionSize,
message: `Size ${order.size} vs limit ${this.config.maxPositionSize}`,
});
// Check 2: Total exposure limit
const newExposure = this.state.currentExposure + order.size * order.price;
checks.push({
name: 'totalExposure',
passed: newExposure <= this.config.maxTotalExposure,
message: `New exposure ${newExposure} vs limit ${this.config.maxTotalExposure}`,
});
// Check 3: Concurrent positions
checks.push({
name: 'concurrentPositions',
passed: this.state.openPositions < this.config.maxConcurrentPositions,
message: `Positions ${this.state.openPositions} vs limit ${this.config.maxConcurrentPositions}`,
});
// Check 4: Daily loss limit
checks.push({
name: 'dailyLoss',
passed: Math.abs(this.state.dailyPnL) < this.config.maxDailyLoss,
message: `Daily P/L ${this.state.dailyPnL} vs limit ${this.config.maxDailyLoss}`,
});
// Check 5: Drawdown limit
const currentDrawdown = (this.state.peakCapital - this.state.currentCapital) / this.state.peakCapital;
checks.push({
name: 'drawdown',
passed: currentDrawdown < this.config.maxDrawdownPercent,
message: `Drawdown ${(currentDrawdown * 100).toFixed(1)}% vs limit ${this.config.maxDrawdownPercent * 100}%`,
});
const allPassed = checks.every(c => c.passed);
return {
allowed: allPassed,
checks,
reason: allPassed ? null : checks.find(c => !c.passed)?.message,
};
}
async emergencyStop(reason: string): Promise<void> {
console.error(`🚨 EMERGENCY STOP: ${reason}`);
// Stop all new orders
this.state.tradingEnabled = false;
// Cancel all open orders
await this.cancelAllOrders();
// Close all positions (market orders)
await this.closeAllPositions();
// Alert
await this.sendAlert({
level: 'CRITICAL',
message: `Bot emergency stopped: ${reason}`,
timestamp: new Date(),
});
}
}
7. Infrastructure Layer
// Multi-RPC with failover
class RPCManager {
private endpoints: RPCEndpoint[];
private activeIndex: number = 0;
private healthChecks: Map<string, HealthStatus> = new Map();
async getConnection(): Promise<Connection> {
// Try active endpoint
const active = this.endpoints[this.activeIndex];
if (this.isHealthy(active)) {
return new Connection(active.url);
}
// Failover to next healthy endpoint
for (let i = 0; i < this.endpoints.length; i++) {
const endpoint = this.endpoints[i];
if (this.isHealthy(endpoint)) {
this.activeIndex = i;
return new Connection(endpoint.url);
}
}
throw new Error('No healthy RPC endpoints available');
}
private async checkHealth(endpoint: RPCEndpoint): Promise<boolean> {
try {
const conn = new Connection(endpoint.url);
const start = Date.now();
await conn.getSlot();
const latency = Date.now() - start;
return latency < endpoint.maxLatency;
} catch {
return false;
}
}
}
// Structured logging
class BotLogger {
log(level: 'DEBUG' | 'INFO' | 'WARN' | 'ERROR', event: string, data: any) {
const entry = {
timestamp: new Date().toISOString(),
level,
event,
...data,
};
console.log(JSON.stringify(entry));
// Also send to external logging service
this.sendToLoggingService(entry);
}
trade(action: 'OPEN' | 'CLOSE', position: Position, result: TradeResult) {
this.log('INFO', 'TRADE', {
action,
token: position.token,
side: position.side,
size: position.size,
entryPrice: position.entryPrice,
exitPrice: result.price,
pnl: result.pnl,
pnlPercent: result.pnlPercent,
executionTime: result.executionTime,
signature: result.signature,
});
}
}
Templates / Playbooks
Bot Configuration Template
const botConfig: BotConfig = {
// Identity
name: 'solana-momentum-bot',
version: '1.0.0',
// Trading parameters
tradingPairs: ['SOL/USDC', 'BONK/SOL'],
maxPositionSize: 1000, // $1000 per position
maxTotalExposure: 5000, // $5000 total
maxConcurrentPositions: 3,
// Risk limits
maxLossPerTrade: 100, // $100 max loss per trade
maxDailyLoss: 500, // $500 max daily loss
maxDrawdownPercent: 0.15, // 15% max drawdown
// Execution
defaultSlippageBps: 100, // 1% default slippage
maxSlippageBps: 300, // 3% max slippage
priorityFeeMicroLamports: 10000,
useJito: true,
jitoTipLamports: 50000, // 0.00005 SOL
// Infrastructure
rpcEndpoints: [
'https://api.mainnet-beta.solana.com',
'https://your-helius-endpoint.com',
],
jitoEndpoint: 'https://mainnet.block-engine.jito.wtf',
// Monitoring
healthCheckInterval: 10000, // 10 seconds
alertWebhook: 'https://your-discord-webhook',
};
Alert Template
interface Alert {
level: 'INFO' | 'WARN' | 'ERROR' | 'CRITICAL';
event: string;
message: string;
data?: any;
}
// Discord webhook format
function formatDiscordAlert(alert: Alert): object {
const colors = {
INFO: 0x00ff00,
WARN: 0xffff00,
ERROR: 0xff8800,
CRITICAL: 0xff0000,
};
return {
embeds: [{
title: `[${alert.level}] ${alert.event}`,
description: alert.message,
color: colors[alert.level],
fields: alert.data ? Object.entries(alert.data).map(([k, v]) => ({
name: k,
value: String(v),
inline: true,
})) : [],
timestamp: new Date().toISOString(),
}],
};
}
Common Failure Modes + Debugging
"Orders keep failing"
- Cause: Stale blockhash, low priority fee, or slippage too tight
- Detection: High failure rate in execution logs
- Fix: Refresh blockhash per order; increase priority fee; widen slippage
"Bot got stuck in position"
- Cause: Exit order failing repeatedly
- Detection: Position age exceeds expected hold time
- Fix: Emergency market sell with high slippage; add escalating slippage on retry
"Unexpected losses"
- Cause: Price moved against position faster than expected
- Detection: Large negative P/L on closed positions
- Fix: Tighter stop-losses; reduce position size; add momentum filters
"Bot stopped trading"
- Cause: Risk limit hit or health check failed
- Detection: No trades for extended period
- Fix: Check risk state; verify RPC health; check wallet balance
"Duplicate orders"
- Cause: Retry logic creating multiple orders
- Detection: Multiple fills for same signal
- Fix: Implement idempotency keys; check position before ordering
Quality Bar / Validation
Implementation is complete when:
- All risk checks enforced before every trade
- Emergency stop tested and working
- Logging captures every decision and execution
- RPC failover tested
- Position tracking accurate
- P/L calculations verified
- Alerts firing correctly
- Graceful shutdown preserves state
Output Format
Provide:
- Architecture diagram: Component overview
- Configuration template: All parameters with defaults
- Core code: Strategy, execution, and risk modules
- Infrastructure setup: RPC, logging, alerting
- Testing checklist: What to verify before going live
Examples
Simple Example: Basic Swap Bot
Input: "Create a simple bot that buys tokens when they pump 10%"
Output:
// Minimal viable trading bot
class SimplePumpBot {
private positions: Map<string, Position> = new Map();
private maxPositionUsd = 100;
private minPumpPercent = 10;
async run() {
while (true) {
// Check watchlist
for (const token of this.watchlist) {
const priceChange = await this.getPriceChange(token, '5m');
// Entry signal
if (priceChange >= this.minPumpPercent && !this.positions.has(token)) {
await this.buy(token, this.maxPositionUsd);
}
// Exit signal (take profit or stop loss)
if (this.positions.has(token)) {
const position = this.positions.get(token);
const pnl = await this.calculatePnL(position);
if (pnl >= 20 || pnl <= -10) { // 20% TP or 10% SL
await this.sell(token);
}
}
}
await this.sleep(5000); // Check every 5 seconds
}
}
private async buy(token: string, usdAmount: number) {
console.log(`BUY ${token} for $${usdAmount}`);
// ... Jupiter swap implementation
}
private async sell(token: string) {
console.log(`SELL ${token}`);
// ... Jupiter swap implementation
}
}
Complex Example: Full Arbitrage Bot
Input: "Design an arb bot that captures price discrepancies across DEXs"
Output: See examples/arb-bot-architecture.md for complete implementation including:
- Multi-DEX price monitoring (Jupiter, Raydium, Orca)
- Atomic execution via Jito bundles
- Profit calculation with fees
- Risk management for inventory
- Performance monitoring dashboard
How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/sanctifiedops/solana-skills/trading-bot-architecture">View trading-bot-architecture on skillZs</a>