A microservices-based AI trading system that monitors Twitter for cryptocurrency signals, analyzes sentiment using large language models, and executes trades on Solana DEX (Raydium). The system uses a decoupled architecture with Redis message streaming for reliable communication between services.
The system consists of two independent microservices communicating via Redis streams:
The sentiment service fetches the top trending Solana tokens from the Raydium API (sorted by 24h trading volume). This drives targeted Twitter searches instead of using a single broad query.
- Fetches from
https://api-v3.raydium.io/pools/info/list?poolSortField=volume24h - Filters out stablecoins and wrapped SOL
- Results are cached in Redis for 15 minutes to avoid excessive API calls
- Configurable: top N tokens, minimum 24h volume threshold
- Falls back to a static
TWITTER_QUERYif the Raydium API is unreachable - Can be disabled entirely with
USE_TRENDING=false
For each trending token, the sentiment service searches Twitter (via RapidAPI) using targeted queries like "$SYMBOL solana". This yields more relevant results than a single generic search.
- Uses Redis to track already-processed tweets (7-day TTL)
- Fetches multiple tweets per search and filters out seen ones
- Prevents wasting LLM calls on repeated content
- Logs:
Fetched X tweets, Y unseen
When an unseen tweet is found, it's analyzed by an AI language model (Ollama or OpenRouter) that:
- Extracts Solana token addresses (validates base58 format)
- Determines sentiment (bullish, bearish, neutral, or spam)
- Assigns a confidence score (0-100) based on signal clarity
- Provides reasoning for the analysis
The service calculates a credibility score for the tweet author based on:
- Number of followers (higher = more credible)
- Verification status (verified users get +30 points)
- Combined score ranges from 0-100
When a trade signal meets criteria, the sentiment service:
- Generates a unique order ID
- Publishes the trade order to Redis
trade_ordersstream - Does NOT execute trades itself (separation of concerns)
- Trades are only published if ALL criteria are met:
- β Valid Solana token address detected
- β Sentiment is bullish
- β Confidence score β₯ MIN_CONFIDENCE (default 60%)
- β Credibility score β₯ MIN_CREDIBILITY (default 30%)
- β Token hasn't been traded before (prevents duplicates)
- Listens on Redis
trade_ordersstream - Receives trade signals from the sentiment service
- Processes orders in real-time using Redis consumer groups
- Paper Trading Mode (default): Logs would-be trades without executing
- Live Trading Mode: Executes real swaps on Solana using Raydium DEX
- Each trade is executed independently and tracked
- Publishes execution results back to Redis
trade_resultsstream - Sentiment service receives confirmations asynchronously
- All trades are logged locally by both services
Sentiment Service Redis Streams Trader Service
β β
βββ Analyze Tweet β
β β
βββ Publish Order βββββββΊ trade_orders ββββββββββΊβ
β β
β Execute Swap
β β
βββββ Result βββββββββββ trade_results βββββββββββ
β β
Log Result Log Result
The bot uses a sophisticated multi-factor analysis:
βββββββββββββββββββ
β Tweet Found β
ββββββββββ¬βββββββββ
β
βΌ
βββββββββββββββββββββββββββ
β AI Sentiment Analysis β
β β’ Token extraction β
β β’ Sentiment (B/B/N/S) β
β β’ Confidence (0-100) β
ββββββββββ¬βββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββ
β Credibility Scoring β
β β’ Follower count β
β β’ Verification status β
ββββββββββ¬βββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββ
β Trade Decision Logic β
β IF bullish AND β
β confidence β₯ 60 AND β
β credibility β₯ 30 β
β THEN execute trade β
ββββββββββ¬βββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββ
β Execute or Simulate β
β β’ Paper: Log only β
β β’ Live: Swap on DEX β
βββββββββββββββββββββββββββ
- Docker & Docker Compose
- Twitter/X API access via RapidAPI
- Solana wallet with private key (for live trading)
- Optional: OpenRouter API key (if not using local Ollama)
-
Clone the repository:
git clone <repository-url> cd velesio-trader
-
Configure environment:
cp .env.example .env nano .env # Edit with your API keys -
Start the services (paper trading mode by default):
docker compose up --build
-
Access the dashboard:
http://localhost:3000 -
View logs:
# Sentiment service docker compose logs -f sentiment # Trader service docker compose logs -f trader # Redis docker compose logs -f redis
- Frontend Dashboard: http://localhost:3000
- Sentiment API: http://localhost:8000
- Trader API: http://localhost:8001
- Ollama: http://localhost:11434
- Redis: localhost:6379
By default, both services run in PAPER TRADING mode - the sentiment service will analyze tweets and publish signals, but the trader service won't execute real trades. You'll see logs like:
Sentiment service:
INFO Searching tweets: solana token
INFO Fetched 15 tweets, 3 unseen
INFO Trade order [abc123] published: 0.0001 SOL β <token_address>
Trader service:
INFO Received trade order [abc123]: 100000 lamports β <token_address> (paper=True)
INFO PAPER TRADE logged: 0.0001 SOL β <token_address>
INFO Result published: paper_executed
To enable live trading (
- Set
PAPER_TRADING=falsein your.envfile - Ensure your wallet has sufficient SOL balance
- Restart the services with
docker compose up --build
Create a .env file in the root directory. Variables are shared between services as needed:
# ββ Sentiment Service Configuration ββββββββββββββββββββββββββββββ
# Twitter API (get from RapidAPI)
RAPIDAPI_KEY=your_rapidapi_key_here
TWITTER_QUERY=solana token # Fallback query when trending is off/unavailable
POLL_INTERVAL=300
# Trending Token Discovery (Raydium API)
USE_TRENDING=true # true = search by trending tokens, false = use TWITTER_QUERY
TRENDING_TOP_N=10 # Number of top tokens to track
TRENDING_MIN_VOLUME=100000 # Minimum 24h volume (USD) to qualify
# Trading Criteria (used by sentiment service)
MIN_CONFIDENCE=60 # Minimum sentiment confidence (0-100)
MIN_CREDIBILITY=30 # Minimum user credibility (0-100)
# LLM Configuration
USE_OLLAMA=true
OLLAMA_MODEL=gemma3
# If using OpenRouter instead:
# USE_OLLAMA=false
# OPENROUTER_API_KEY=your_key_here
# ββ Trader Service Configuration ββββββββββββββββββββββββββββββ
# Solana Configuration (required for live trading)
PRIVATE_KEY=[your,solana,private,key,array]
RPC_URL=https://api.mainnet-beta.solana.com
# ββ Shared Configuration ββββββββββββββββββββββββββββββββββββββ
# Paper Trading Mode (affects both services)
PAPER_TRADING=true # true = simulate, false = execute real trades
# Trade Amount
SOL_AMOUNT=0.0001 # Amount of SOL per trade
# Redis Connection (auto-configured in docker-compose)
REDIS_HOST=redis
REDIS_PORT=6379
# Bot Auto-start (optional)
AUTO_START_BOT=false # true = bot starts automatically with containerNote: The sentiment service uses Twitter/LLM configs, while the trader service uses Solana configs. Both services share the PAPER_TRADING setting to ensure consistency.
Control trading aggressiveness by adjusting thresholds:
# Conservative (fewer trades, higher quality)
MIN_CONFIDENCE=80
MIN_CREDIBILITY=60
# Moderate (balanced)
MIN_CONFIDENCE=60
MIN_CREDIBILITY=30
# Aggressive (more trades, higher risk)
MIN_CONFIDENCE=40
MIN_CREDIBILITY=20Target specific signals by customizing the Twitter search:
# Monitor specific user
TWITTER_QUERY=from:vitalik.eth solana
# Search for buy signals
TWITTER_QUERY="just bought" OR "bullish on" crypto
# Target specific tokens
TWITTER_QUERY=#SOL OR #Solana new tokenBoth services maintain their own trade history logs:
# View trade signals published
docker compose exec sentiment cat trade_history.json | tail -n 50
# Copy to local machine
docker cp sentiment:/app/trade_history.json ./sentiment_history.json# View executed trades (includes tx IDs)
docker compose exec trader cat trade_history.json 2>/dev/null || echo "No history yet"
# The trader service logs are in-memory by default
# Check logs for execution details:
docker compose logs trader | grep "Trade executed"# View pending trade orders
docker compose exec redis redis-cli XLEN trade_orders
# View recent trade results
docker compose exec redis redis-cli XREVRANGE trade_results + - COUNT 10
# Check seen tweets count
docker compose exec redis redis-cli SCARD seen_tweetsExample sentiment service record:
{
"timestamp": "2026-02-10T21:15:30.123456",
"token_address": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
"sentiment": "bullish",
"confidence": 75,
"credibility_score": 85,
"reasoning": "Clear buy signal with verified Solana token address",
"executed": false,
"paper_trade": true,
"amount_sol": 0.0001
}Example trader service execution log:
INFO Received trade order [a1b2c3d4]: 100000 lamports β 7xKXt... (paper=True)
INFO PAPER TRADE logged: 0.0001 SOL β 7xKXt...
INFO Result published: paper_executed
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Docker Compose Stack β
ββββββββββββββββββββ¬βββββββββββββββββββ¬βββββββββββββββββββ¬βββββββββββββ€
β Redis β Sentiment β Trader β Ollama β
β Container β Service β Service β Container β
β β β β β
β β’ Streams β β’ Tweet fetch β β’ Order consume β β’ LLM API β
β β’ Pub/Sub β β’ Analysis β β’ Swap execute β β’ gemma3 β
β β’ Dedup cache β β’ Order publish β β’ Result report β β
β Port: 6379 β Port: 8000 β Port: 8001 β Port: 11434β
ββββββββββ¬ββββββββββ΄βββββββββ¬ββββββββββ΄βββββββββ¬ββββββββββ΄βββββββββββββ
β β β
β βββββββββββββββΌβββββββββββββββββββΌβββββββββ
β β β β β
ββββββΌβββββΌβββ ββββββββΌβββββββ ββββββββΌβββββββ β
β Stream 1 β β Twitter API β β LLM API β β
βtrade_ordersβ β (RapidAPI) β β (Ollama) β β
ββββββ¬ββββββββ βββββββββββββββ βββββββββββββββ β
β β
ββββββΌβββββββββ βββββββββββΌβββββββ
β Stream 2 β β Solana RPC β
βtrade_resultsβ β (Raydium) β
βββββββββββββββ ββββββββββββββββββ
β
ββββββΌββββββββ
β Redis Set β
βseen_tweets β
ββββββββββββββ
Sentiment Service:
- Twitter monitoring and tweet fetching
- LLM-based sentiment analysis
- Token address extraction and validation
- Credibility scoring
- Trade signal generation
- Publishing orders to Redis
- Receiving execution confirmations
Trader Service:
- Consuming trade orders from Redis
- Executing Solana swaps via Raydium
- Managing Solana wallet and transactions
- Publishing execution results
- Paper trading simulation
Redis:
- Message broker between services
trade_ordersstream (Sentiment β Trader)trade_resultsstream (Trader β Sentiment)seen_tweetsset for deduplication- Reliable delivery with consumer groups
Frontend:
- React dashboard (port 3000)
- Real-time logs via WebSocket
- Start/stop bot controls
- Trade history display
- Connects to Sentiment service API
-
Never commit
.envfile - it contains your private keysecho ".env" >> .gitignore
-
Use dedicated trading wallet - don't use your main wallet
solana-keygen new -o trading-wallet.json
-
Start with small amounts - test with minimal SOL first
# In main.py, adjust SOL_AMOUNT SOL_AMOUNT = int(0.0001 * LAMPORTS_PER_SOL) # 0.0001 SOL
-
Monitor actively - watch logs when first deploying
docker compose logs -f trading-bot
-
Regular backups - save trade history periodically
docker cp trading-bot:/app/trade_history.json ./backups/
Each service has its own API for monitoring:
# Sentiment service status
curl http://localhost:8000/api/status
# Trader service status
curl http://localhost:8001/api/status
# View real-time logs via WebSocket
# Connect to ws://localhost:8000/ws/logs (sentiment)
# Connect to ws://localhost:8001/ws/logs (trader)The microservices architecture allows independent scaling:
Multiple Sentiment Services (different queries):
# docker-compose.yml
services:
sentiment-sol:
extends: sentiment
container_name: sentiment-sol
environment:
- TWITTER_QUERY=solana new token
sentiment-memes:
extends: sentiment
container_name: sentiment-memes
environment:
- TWITTER_QUERY=memecoin launchMultiple Trader Services (load distribution):
services:
trader-1:
extends: trader
container_name: trader-1
trader-2:
extends: trader
container_name: trader-2Both will consume from the same Redis stream using consumer groups, automatically load-balancing orders.
The sentiment service supports any Ollama-compatible model:
# Pull a different model
docker exec -it ollama ollama pull mistral
# Update .env
OLLAMA_MODEL=mistral
# Restart sentiment service
docker compose restart sentimentTo persist Redis data across restarts:
# docker-compose.yml
services:
redis:
volumes:
- redis_data:/data
command: redis-server --appendonly yesExport trades for analysis:
import json
import pandas as pd
# Combine data from both services
with open('sentiment_history.json') as f:
signals = json.load(f)
with open('trader_history.json') as f:
executions = json.load(f)
df_signals = pd.DataFrame(signals)
df_executions = pd.DataFrame(executions)
# Merge on order_id or timestamp
print(df_signals.describe())
print(df_executions.describe())Symptom: Sentiment service publishes orders but trader doesn't execute
# Check Redis is running
docker compose ps redis
# Verify Redis connection
docker compose exec redis redis-cli ping
# Check trade_orders stream
docker compose exec redis redis-cli XLEN trade_orders
# If orders are piling up, check trader logs
docker compose logs traderSymptom: Same tweet analyzed multiple times
# Check seen_tweets set size
docker compose exec redis redis-cli SCARD seen_tweets
# Verify TTL is set
docker compose exec redis redis-cli TTL seen_tweets
# Clear seen tweets if needed (will reprocess everything)
docker compose exec redis redis-cli DEL seen_tweetsLLM not detecting token addresses:
- Try more specific search query:
TWITTER_QUERY="CA:" solana - Use a more powerful model:
OLLAMA_MODEL=llama3 - Check Ollama logs:
docker compose logs ollama
No tweets found:
- Check RapidAPI subscription status
- Verify
RAPIDAPI_KEYis correct - Try broader search query
- Check sentiment service logs:
docker compose logs sentiment
All tweets already processed:
- This is normal! The system is working correctly
- Wait for new tweets matching your query
- Reduce
POLL_INTERVALto check more frequently - Or change
TWITTER_QUERYto search different content
Trades not executing:
- Check
PAPER_TRADING=falsefor live trading - Verify trader service is running:
docker compose ps trader - Check wallet has SOL balance
- Review trader logs:
docker compose logs trader
Order consumption errors:
- Restart trader service:
docker compose restart trader - Check Redis consumer groups:
docker compose exec redis redis-cli XINFO GROUPS trade_orders
Connection errors:
# Restart Redis
docker compose restart redis
# Check both services reconnect
docker compose logs -f sentiment trader | grep "Redis connection"Memory issues:
# Check Redis memory usage
docker compose exec redis redis-cli INFO memory
# Clear old data
docker compose exec redis redis-cli FLUSHDBModel errors:
- Increase Docker memory allocation (minimum 4GB recommended)
- Pull model manually:
docker exec -it ollama ollama pull gemma3 - Try a smaller model:
OLLAMA_MODEL=gemma2:2b
# Check frontend service
docker compose ps frontend
# Verify nginx proxy config
docker compose logs frontend
# Test API endpoints directly
curl http://localhost:8000/api/status
curl http://localhost:8001/api/statusSeparation of Concerns:
- Sentiment service focuses on analysis and signal generation
- Trader service focuses on execution and blockchain interaction
- Each service can be developed, tested, and deployed independently
Reliability:
- If the trader crashes, sentiment analysis continues
- If sentiment service restarts, trader keeps processing queued orders
- Redis streams provide guaranteed message delivery
Scalability:
- Run multiple sentiment services for different Twitter queries
- Run multiple trader services for parallel execution
- Scale each component based on load
Resource Efficiency:
- Trader service doesn't need LLM dependencies
- Sentiment service doesn't need Solana/crypto libraries
- Deduplication prevents wasted LLM calls on repeated tweets
Testing & Development:
- Test services independently
- Mock Redis streams for unit testing
- Easy to add new services (e.g., a separate analytics service)
MIT License - see LICENSE file for details
This bot is for educational purposes only. Cryptocurrency trading carries significant risk. Always:
- Start with paper trading mode
- Never invest more than you can afford to lose
- Do your own research (DYOR)
- Be aware of rug pulls and scams
- This is not financial advice
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Submit a pull request
For issues and questions:
- Open a GitHub issue
- Check existing discussions
- Review the troubleshooting section
Built with β€οΈ for the Solana community