Skip to content

Instantly share code, notes, and snippets.

@andrewxhill
Created March 7, 2025 00:02
Show Gist options
  • Save andrewxhill/9ee80495ec724697abf0c7465eaa4ed6 to your computer and use it in GitHub Desktop.
Save andrewxhill/9ee80495ec724697abf0c7465eaa4ed6 to your computer and use it in GitHub Desktop.
setup a basic recall agent
#!/bin/bash
# =============================================================================
# Crypto Trading Opportunity Detection Agent Setup Script
# Created by: Claude Code
# Version: 1.0.0
# =============================================================================
# Color definitions for better readability
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# Print banner
echo -e "${BLUE}=================================================================${NC}"
echo -e "${BLUE} Crypto Trading Opportunity Detection Agent Setup Script ${NC}"
echo -e "${BLUE}=================================================================${NC}"
echo -e "${YELLOW}This script will help you set up a complete crypto trading agent${NC}"
echo -e "${YELLOW}using the Recall Agent Starter kit and Eliza framework. ${NC}"
echo -e "${BLUE}=================================================================${NC}"
# Function to check if a command exists
command_exists() {
command -v "$1" &> /dev/null
}
# Function to check dependencies
check_dependencies() {
echo -e "\n${CYAN}Checking dependencies...${NC}"
# Check for Node.js
if ! command_exists node; then
echo -e "${RED}Node.js is not installed. Please install Node.js v22 or later.${NC}"
echo -e "${YELLOW}Visit: https://nodejs.org/en/download/${NC}"
exit 1
fi
NODE_VERSION=$(node -v | cut -d'.' -f1 | sed 's/v//')
if [[ $NODE_VERSION -lt 22 ]]; then
echo -e "${RED}Node.js version 22 or later is required. You have version $NODE_VERSION.${NC}"
echo -e "${YELLOW}Please upgrade your Node.js installation.${NC}"
exit 1
fi
echo -e "${GREEN}✓ Node.js v$(node -v) is installed${NC}"
# Check for pnpm
if ! command_exists pnpm; then
echo -e "${YELLOW}pnpm is not installed. Would you like to install it? (y/n)${NC}"
read -r install_pnpm
if [[ $install_pnpm == "y" ]]; then
echo -e "${YELLOW}Installing pnpm...${NC}"
npm install -g pnpm
else
echo -e "${RED}pnpm is required to continue. Please install manually and run this script again.${NC}"
echo -e "${YELLOW}You can install pnpm with: npm install -g pnpm${NC}"
exit 1
fi
fi
echo -e "${GREEN}✓ pnpm is installed${NC}"
# Check for git
if ! command_exists git; then
echo -e "${RED}Git is not installed. Please install Git and try again.${NC}"
echo -e "${YELLOW}Visit: https://git-scm.com/downloads${NC}"
exit 1
fi
echo -e "${GREEN}✓ Git is installed${NC}"
}
# Function to clone the repo
clone_repo() {
echo -e "\n${CYAN}Setting up agent repository...${NC}"
# Ask for agent name
echo -e "${YELLOW}Enter a name for your trading agent (e.g., crypto-trading-agent):${NC}"
read -r agent_name
agent_name=${agent_name:-"crypto-trading-agent"}
# Make safe directory name
safe_name=$(echo "$agent_name" | tr -cd '[:alnum:]._-' | tr '[:upper:]' '[:lower:]')
# Check if directory already exists
if [[ -d "$safe_name" ]]; then
echo -e "${YELLOW}Directory '$safe_name' already exists. What would you like to do?${NC}"
echo -e "1. Use existing directory"
echo -e "2. Create a new directory with a different name"
echo -e "3. Exit"
read -r dir_choice
case $dir_choice in
1)
echo -e "${YELLOW}Using existing directory '$safe_name'${NC}"
cd "$safe_name" || exit 1
;;
2)
echo -e "${YELLOW}Enter a new name:${NC}"
read -r new_name
safe_name=$(echo "$new_name" | tr -cd '[:alnum:]._-' | tr '[:upper:]' '[:lower:]')
if [[ -d "$safe_name" ]]; then
echo -e "${RED}Directory '$safe_name' also exists. Please run the script again with a different name.${NC}"
exit 1
fi
mkdir -p "$safe_name"
cd "$safe_name" || exit 1
git clone https://github.com/recallnet/recall-agent-starter.git .
if [ $? -ne 0 ]; then
echo -e "${RED}Failed to clone repository. Please check your internet connection and try again.${NC}"
cd ..
rmdir "$safe_name"
exit 1
fi
;;
3)
echo -e "${YELLOW}Exiting script.${NC}"
exit 0
;;
*)
echo -e "${RED}Invalid choice. Exiting.${NC}"
exit 1
;;
esac
else
# Create directory and clone
echo -e "${YELLOW}Creating new directory '$safe_name' and cloning repository...${NC}"
mkdir -p "$safe_name"
cd "$safe_name" || exit 1
git clone https://github.com/recallnet/recall-agent-starter.git .
if [ $? -ne 0 ]; then
echo -e "${RED}Failed to clone repository. Please check your internet connection and try again.${NC}"
cd ..
rmdir "$safe_name"
exit 1
fi
fi
echo -e "${GREEN}✓ Repository setup complete${NC}"
}
# Function to set up environment variables
setup_environment() {
echo -e "\n${CYAN}Setting up environment variables...${NC}"
# Create .env file if it doesn't exist
if [ ! -f .env ]; then
if [ -f .env.example ]; then
cp .env.example .env
echo -e "${GREEN}✓ Created .env file from template${NC}"
else
touch .env
echo -e "${GREEN}✓ Created empty .env file${NC}"
fi
else
echo -e "${YELLOW}Using existing .env file${NC}"
fi
# LLM API Keys
echo -e "\n${YELLOW}Setting up API keys for language models...${NC}"
echo -e "You'll need at least one API key to use language models with your agent."
# Check for existing API keys
if grep -q "OPENAI_API_KEY" .env; then
echo -e "${YELLOW}OpenAI API key already exists in .env file.${NC}"
echo -e "${YELLOW}Would you like to update it? (y/n)${NC}"
read -r update_openai
if [[ $update_openai == "y" ]]; then
echo -e "${YELLOW}Enter your OpenAI API key:${NC}"
read -r openai_key
sed -i.bak "s/OPENAI_API_KEY=.*/OPENAI_API_KEY=$openai_key/" .env
rm -f .env.bak
echo -e "${GREEN}✓ OpenAI API key updated${NC}"
fi
else
echo -e "${YELLOW}Would you like to use OpenAI models (recommended for crypto analysis)? (y/n)${NC}"
read -r use_openai
if [[ $use_openai == "y" ]]; then
echo -e "${YELLOW}Enter your OpenAI API key:${NC}"
read -r openai_key
echo "OPENAI_API_KEY=$openai_key" >> .env
echo -e "${GREEN}✓ OpenAI API key added${NC}"
fi
fi
# Check for existing Anthropic key
if grep -q "ANTHROPIC_API_KEY" .env; then
echo -e "${YELLOW}Anthropic API key already exists in .env file.${NC}"
echo -e "${YELLOW}Would you like to update it? (y/n)${NC}"
read -r update_anthropic
if [[ $update_anthropic == "y" ]]; then
echo -e "${YELLOW}Enter your Anthropic API key:${NC}"
read -r anthropic_key
sed -i.bak "s/ANTHROPIC_API_KEY=.*/ANTHROPIC_API_KEY=$anthropic_key/" .env
rm -f .env.bak
echo -e "${GREEN}✓ Anthropic API key updated${NC}"
fi
else
echo -e "${YELLOW}Would you like to use Anthropic Claude models? (y/n)${NC}"
read -r use_anthropic
if [[ $use_anthropic == "y" ]]; then
echo -e "${YELLOW}Enter your Anthropic API key:${NC}"
read -r anthropic_key
echo "ANTHROPIC_API_KEY=$anthropic_key" >> .env
echo -e "${GREEN}✓ Anthropic API key added${NC}"
fi
fi
# Set default model if not already set
if ! grep -q "DEFAULT_MODEL" .env; then
if [[ $use_openai == "y" ]]; then
echo "DEFAULT_MODEL=gpt-4o" >> .env
echo -e "${GREEN}✓ Default model set to gpt-4o${NC}"
elif [[ $use_anthropic == "y" ]]; then
echo "DEFAULT_MODEL=claude-3-opus-20240229" >> .env
echo -e "${GREEN}✓ Default model set to claude-3-opus${NC}"
else
echo "DEFAULT_MODEL=gpt-4o" >> .env
echo -e "${YELLOW}⚠ Default model set to gpt-4o, but no API key provided${NC}"
fi
fi
# Set other default configs if not present
if ! grep -q "CACHE_STORE" .env; then
echo "CACHE_STORE=FS" >> .env
fi
if ! grep -q "DATABASE" .env; then
echo "DATABASE=sqlite" >> .env
fi
if ! grep -q "SERVER_PORT" .env; then
echo "SERVER_PORT=3000" >> .env
fi
# Recall Network setup
echo -e "\n${CYAN}Setting up Recall Network storage...${NC}"
echo -e "${YELLOW}Recall Network is used to persistently store trading signals and analysis results.${NC}"
echo -e "${YELLOW}Would you like to set up Recall Network integration? (y/n)${NC}"
read -r setup_recall
if [[ $setup_recall == "y" ]]; then
echo -e "${BLUE}To use Recall Network, you'll need:${NC}"
echo -e "${BLUE}1. A private key (available from the faucet)${NC}"
echo -e "${BLUE}2. A bucket to store your trading signals${NC}"
# Check for existing Recall settings
if grep -q "RECALL_PRIVATE_KEY" .env; then
echo -e "${YELLOW}Recall private key already exists in .env file.${NC}"
existing_key=$(grep "RECALL_PRIVATE_KEY" .env | cut -d'=' -f2)
# Show a few characters of the key for confirmation
if [[ ${#existing_key} -gt 10 ]]; then
echo -e "${YELLOW}Current key: ${existing_key:0:6}...${existing_key: -4}${NC}"
fi
echo -e "${YELLOW}Would you like to update it? (y/n)${NC}"
read -r update_recall_key
if [[ $update_recall_key == "y" ]]; then
echo -e "${YELLOW}Enter your Recall private key:${NC}"
read -r recall_key
sed -i.bak "s/RECALL_PRIVATE_KEY=.*/RECALL_PRIVATE_KEY=$recall_key/" .env
rm -f .env.bak
echo -e "${GREEN}✓ Recall private key updated${NC}"
else
recall_key=$existing_key
fi
else
echo -e "${YELLOW}Enter your Recall private key (or leave blank to get one from faucet):${NC}"
read -r recall_key
if [[ -z "$recall_key" ]]; then
echo -e "${BLUE}Please visit: ${YELLOW}https://faucet.recall.network/${NC}"
echo -e "${BLUE}to create a new account and receive your private key.${NC}"
echo -e "${YELLOW}Enter the private key you received:${NC}"
read -r recall_key
fi
echo "RECALL_PRIVATE_KEY=$recall_key" >> .env
echo -e "${GREEN}✓ Recall private key added${NC}"
fi
# Set up bucket name
if grep -q "RECALL_BUCKET_NAME" .env; then
existing_bucket=$(grep "RECALL_BUCKET_NAME" .env | cut -d'=' -f2)
echo -e "${YELLOW}Current bucket: $existing_bucket${NC}"
echo -e "${YELLOW}Would you like to update it? (y/n)${NC}"
read -r update_bucket
if [[ $update_bucket == "y" ]]; then
echo -e "${YELLOW}Enter your bucket name (e.g., trading-signals):${NC}"
read -r bucket_name
sed -i.bak "s/RECALL_BUCKET_NAME=.*/RECALL_BUCKET_NAME=$bucket_name/" .env
rm -f .env.bak
echo -e "${GREEN}✓ Bucket name updated${NC}"
fi
else
echo -e "${YELLOW}Enter a name for your storage bucket (e.g., trading-signals):${NC}"
read -r bucket_name
bucket_name=${bucket_name:-"trading-signals"}
echo "RECALL_BUCKET_NAME=$bucket_name" >> .env
echo -e "${GREEN}✓ Bucket name added${NC}"
fi
# Ask if they need funding
echo -e "\n${YELLOW}Do you need to get tokens from the Recall faucet? (y/n)${NC}"
read -r need_funding
if [[ $need_funding == "y" ]]; then
echo -e "${BLUE}Please visit: ${YELLOW}https://faucet.recall.network/${NC}"
echo -e "${BLUE}Using your private key: ${YELLOW}${recall_key:0:6}...${recall_key: -4}${NC}"
echo -e "${BLUE}to receive tokens for storage operations.${NC}"
echo -e "${YELLOW}Press Enter once you've received tokens from the faucet${NC}"
read -r
fi
fi
echo -e "${GREEN}✓ Environment setup complete${NC}"
}
# Function to install dependencies
install_dependencies() {
echo -e "\n${CYAN}Installing dependencies...${NC}"
pnpm install
if [ $? -ne 0 ]; then
echo -e "${RED}Failed to install dependencies. Please check the error message above.${NC}"
exit 1
fi
echo -e "${GREEN}✓ Dependencies installed successfully${NC}"
# Fix version specifiers for critical dependencies
echo -e "\n${CYAN}Ensuring compatible version specifiers for critical dependencies...${NC}"
if grep -q "\"better-sqlite3\": \"[0-9]" package.json; then
echo -e "${YELLOW}Updating better-sqlite3 to use semver compatibility...${NC}"
# Use perl for the replacement since it handles the JSON format better
perl -i -pe 's/"better-sqlite3": "(\d+\.\d+\.\d+)"/"better-sqlite3": "^$1"/g' package.json
echo -e "${GREEN}✓ Updated better-sqlite3 version specifier${NC}"
fi
# Install updates based on the modified package.json
echo -e "${YELLOW}Refreshing dependencies with updated version specifiers...${NC}"
pnpm install
echo -e "${GREEN}✓ Dependency versions updated for compatibility${NC}"
}
# Function to configure crypto specific plugins
configure_crypto_plugins() {
echo -e "\n${CYAN}Setting up crypto trading plugins...${NC}"
# Create plugins directory if it doesn't exist
mkdir -p "src/plugins" 2>/dev/null
# Array of crypto-related plugins with descriptions
declare -a plugins=(
"plugin-coingecko:CoinGecko API integration for cryptocurrency market data"
"plugin-coinmarketcap:CoinMarketCap API for market data and trending coins"
"plugin-web-search:Web search capabilities for crypto news and market developments"
"plugin-twitter:Twitter integration for tracking crypto discussions and announcements"
"plugin-evm:Ethereum Virtual Machine integration for on-chain analytics"
"plugin-binance:Binance exchange API integration for trading and market data"
"plugin-coinbase:Coinbase exchange API integration for trading and market data"
"plugin-rabbi-trader:Trading strategy implementation and backtesting"
"plugin-zerion:Portfolio tracking and analytics"
)
# Check for existing plugins directory structure
existing_plugins=()
plugins_index="src/plugins/index.ts"
if [[ -f "$plugins_index" ]]; then
echo -e "${YELLOW}Found existing plugins configuration.${NC}"
# Extract plugin names from the file
while read -r plugin_line; do
if [[ "$plugin_line" =~ import[[:space:]]+\{[[:space:]]+([a-zA-Z0-9_-]+)Plugin ]]; then
plugin_id="${BASH_REMATCH[1]}"
existing_plugins+=("$plugin_id")
echo -e "${GREEN}✓ Already configured: ${plugin_id}${NC}"
fi
done < "$plugins_index"
fi
# Core plugins that are essential for crypto trading
core_plugins=("plugin-coingecko" "plugin-web-search" "plugin-rabbi-trader")
# Array to collect selected plugins
selected_plugins=()
# Add all existing plugins to selected plugins
for plugin in "${existing_plugins[@]}"; do
selected_plugins+=("$plugin")
done
# Present plugin options
echo -e "\n${YELLOW}Available plugins for crypto trading:${NC}"
for plugin in "${plugins[@]}"; do
name="${plugin%%:*}"
description="${plugin#*:}"
plugin_id=$(echo "$name" | tr '[:upper:]' '[:lower:]' | tr ' ' '-')
# Check if plugin is already installed
already_installed=false
for existing in "${existing_plugins[@]}"; do
if [[ "$existing" == "$plugin_id" ]]; then
already_installed=true
break
fi
done
if [[ "$already_installed" == true ]]; then
echo -e "\n${BLUE}${name}${NC} ${GREEN}[ENABLED]${NC}"
echo -e "${YELLOW}${description}${NC}"
continue
fi
# Automatically select core plugins unless user opts out
is_core=false
for core in "${core_plugins[@]}"; do
if [[ "$core" == "$plugin_id" ]]; then
is_core=true
break
fi
done
echo -e "\n${BLUE}${name}${NC}"
echo -e "${YELLOW}${description}${NC}"
if [[ "$is_core" == true ]]; then
echo -e "${CYAN}This is a core plugin recommended for crypto trading.${NC}"
echo -e "Add this plugin? (Y/n)"
read -r add_plugin
add_plugin=${add_plugin:-"y"}
else
echo -e "Add this plugin? (y/n)"
read -r add_plugin
fi
if [[ $add_plugin == "y" || $add_plugin == "Y" ]]; then
# Check if the plugin file already exists (might be from recall-agent-starter)
plugin_file="src/plugin-${plugin_id}/index.ts"
fallback_file="src/plugins/plugin-${plugin_id}.ts"
if [[ -f "$plugin_file" ]]; then
echo -e "${GREEN}✓ Using existing plugin: ${plugin_file}${NC}"
selected_plugins+=("$plugin_id")
elif [[ -f "$fallback_file" ]]; then
echo -e "${GREEN}✓ Using existing plugin: ${fallback_file}${NC}"
selected_plugins+=("$plugin_id")
else
# Install the plugin as a dependency
echo -e "${YELLOW}Installing ${plugin_id} as a npm dependency...${NC}"
# Get the package name
package_name="@elizaos-plugins/${plugin_id}"
# Look up the repo URL from the registry index or use default
# First check current directory structure
if [[ -f "../../registry/index.json" ]]; then
REGISTRY_INDEX_PATH="../../registry/index.json"
elif [[ -f "../registry/index.json" ]]; then
REGISTRY_INDEX_PATH="../registry/index.json"
elif [[ -f "/Users/andrewhill/Coding/agentmono/registry/index.json" ]]; then
REGISTRY_INDEX_PATH="/Users/andrewhill/Coding/agentmono/registry/index.json"
else
REGISTRY_INDEX_PATH=""
fi
# Find the GitHub repository for this plugin
github_repo="elizaos-plugins/${plugin_id}"
if [[ -f "$REGISTRY_INDEX_PATH" ]]; then
echo -e "${YELLOW}Looking up ${plugin_id} in registry index...${NC}"
# Look for the package in the registry
if grep -q "\"${package_name}\":" "$REGISTRY_INDEX_PATH"; then
# Extract the GitHub repository from the registry
repo_line=$(grep -A1 "\"${package_name}\":" "$REGISTRY_INDEX_PATH" | grep "github:")
if [[ "$repo_line" =~ github:([^\"]*) ]]; then
github_repo="${BASH_REMATCH[1]}"
echo -e "${GREEN}Found GitHub repo: ${github_repo} for ${package_name}${NC}"
fi
else
echo -e "${YELLOW}Using default GitHub repo: ${github_repo}${NC}"
fi
fi
# Install the plugin as a dependency from GitHub
echo -e "${YELLOW}Installing plugin from GitHub: ${github_repo}${NC}"
# Try to install the package directly from GitHub with semver compatibility
pnpm add "github:${github_repo}" --save
if [ $? -ne 0 ]; then
echo -e "${RED}Failed to install ${plugin_id} from GitHub.${NC}"
echo -e "${YELLOW}Consider installing it manually later.${NC}"
else
echo -e "${GREEN}Successfully installed ${plugin_id} as a dependency${NC}"
# Get clean plugin name for later use in plugins index.ts
clean_plugin_name=$(echo "$plugin_id" | sed 's/^plugin-//' | sed 's/-//g')
fi
echo -e "${GREEN}✓ Added plugin: ${plugin_id}${NC}"
selected_plugins+=("$plugin_id")
fi
fi
done
# Create plugins index file if we have selected plugins
if [ ${#selected_plugins[@]} -gt 0 ]; then
echo -e "\n${GREEN}Configuring plugins for your crypto trading agent...${NC}"
# Directly update the index.ts file to include the plugins
index_file="src/index.ts"
# Check if index.ts file exists
if [[ ! -f "$index_file" ]]; then
echo -e "${RED}Cannot find src/index.ts. Plugin integration will be limited.${NC}"
# Create a basic plugins/index.ts file as fallback
echo "// Trading Plugins Integration" > "$plugins_index"
echo "export const tradingPlugins = [];" >> "$plugins_index"
else
# First check if our plugins are already integrated
if ! grep -q "tradingPlugins" "$index_file"; then
echo -e "${YELLOW}Adding plugin imports to index.ts...${NC}"
fi
# Create plugins/index.ts to export tradingPlugins - always recreate this file with the current plugins
echo -e "${YELLOW}Creating plugin imports in plugins/index.ts...${NC}"
# Start fresh to avoid duplicate imports
echo "// Trading Plugins Integration - Imports from node_modules" > "$plugins_index"
# Add imports directly from node_modules
for plugin_id in "${selected_plugins[@]}"; do
# Extract clean plugin name (remove plugin- prefix and hyphens)
clean_plugin_name=$(echo "$plugin_id" | sed 's/^plugin-//' | sed 's/-//g')
# Import directly from node_modules
echo "
// Import ${plugin_id} from npm
let ${clean_plugin_name}Plugin;
try {
const npmModule = require('@elizaos-plugins/${plugin_id}');
${clean_plugin_name}Plugin = npmModule.default || npmModule;
} catch (e) {
console.warn('Could not load ${plugin_id}, using placeholder');
${clean_plugin_name}Plugin = {
name: '${plugin_id}',
version: '0.1.0',
initialize: async () => ({ actions: [] })
};
}" >> "$plugins_index"
done
# Add export statement
echo -e "\nexport const tradingPlugins = [" >> "$plugins_index"
for plugin_id in "${selected_plugins[@]}"; do
# Extract clean plugin name
clean_plugin_name=$(echo "$plugin_id" | sed 's/^plugin-//' | sed 's/-//g')
echo " ${clean_plugin_name}Plugin," >> "$plugins_index"
done
echo "];" >> "$plugins_index"
# Now add import for tradingPlugins to the top of index.ts if not already there
if ! grep -q "import { tradingPlugins }" "$index_file"; then
if [[ "$(uname)" == "Darwin" ]]; then
# macOS requires different sed syntax
sed -i '' '1i\
import { tradingPlugins } from "./plugins";
' "$index_file"
else
# Linux sed syntax
sed -i '1i import { tradingPlugins } from "./plugins";' "$index_file"
fi
fi
# Add plugins to the plugins array in the createAgent function
plugins_line=$(grep -n "plugins: \[" "$index_file" | head -1 | cut -d':' -f1)
if [[ -n "$plugins_line" ]]; then
# Add ...tradingPlugins after the opening bracket
next_line=$((plugins_line + 1))
if ! grep -q "...tradingPlugins" "$index_file"; then
if [[ "$(uname)" == "Darwin" ]]; then
# macOS requires different sed syntax
sed -i '' "${next_line}i\\ ...tradingPlugins," "$index_file"
else
# Linux sed syntax
sed -i "${next_line}i\\ ...tradingPlugins," "$index_file"
fi
fi
fi
fi
echo -e "${GREEN}✓ Created plugins index at ${plugins_index}${NC}"
# This integration is now handled earlier in the script
echo -e "${GREEN}✓ Plugin integration complete${NC}"
fi
echo -e "${GREEN}✓ Crypto plugins setup complete${NC}"
}
# Function to set up character
setup_character() {
echo -e "\n${CYAN}Setting up crypto trading agent character...${NC}"
# Ensure characters directory exists
mkdir -p "characters" 2>/dev/null
# Check for crypto-analyst character
if [[ -f "characters/crypto-analyst.character.json" ]]; then
echo -e "${GREEN}Found existing CryptoAnalyst character.${NC}"
echo -e "${YELLOW}Would you like to use this character for your trading agent? (Y/n)${NC}"
read -r use_crypto_analyst
use_crypto_analyst=${use_crypto_analyst:-"y"}
if [[ $use_crypto_analyst == "y" || $use_crypto_analyst == "Y" ]]; then
character_file="characters/crypto-analyst.character.json"
character_name="crypto-analyst"
echo -e "${GREEN}✓ Using CryptoAnalyst character${NC}"
else
create_new_character=true
fi
else
echo -e "${YELLOW}No crypto trading character found.${NC}"
echo -e "${YELLOW}Would you like to create a custom trading character? (Y/n)${NC}"
read -r create_char
create_char=${create_char:-"y"}
if [[ $create_char == "y" || $create_char == "Y" ]]; then
create_new_character=true
else
# Create a basic CryptoAnalyst character
cat > "characters/crypto-analyst.character.json" << EOF
{
"name": "CryptoAnalyst",
"plugins": [],
"clients": [],
"modelProvider": "openai",
"settings": {
"secrets": {},
"voice": {
"model": "en_US-hfc_female-medium"
}
},
"system": "You are CryptoAnalyst, an expert in detecting cryptocurrency trading opportunities through technical analysis, news monitoring, and social sentiment analysis.",
"bio": [
"Veteran cryptocurrency trader with experience analyzing market cycles since 2013. Specializes in identifying early-stage opportunities and catalysts that drive significant price action.",
"Technical analyst who combines traditional chart patterns with on-chain metrics to identify optimal entry and exit points.",
"Former institutional trader who now focuses on crypto markets and DeFi protocols. Deep knowledge of market microstructure and liquidity dynamics."
],
"lore": [
"Once predicted a major market reversal based solely on analyzing whale wallet movements, saving clients millions.",
"Known for creating the 'Triple Confirmation Strategy' that requires alignment of technical, on-chain, and sentiment indicators before entering positions.",
"Maintains a comprehensive database of historical crypto market cycles and their correlation with traditional markets.",
"Created an algorithm to detect unusual exchange inflows that precede significant price movements."
],
"messageExamples": [
[
{
"user": "{{user1}}",
"content": {
"text": "What do you think about Bitcoin right now?"
}
},
{
"user": "CryptoAnalyst",
"content": {
"text": "Let me analyze the current market structure. BTC shows consolidation above the 200-day moving average, with decreasing exchange balances suggesting accumulation. Key resistance at $52K needs to be cleared for continued bullish momentum. Risk-reward is favorable for long positions with tight stops at $42K."
}
}
],
[
{
"user": "{{user1}}",
"content": {
"text": "Are there any promising altcoins to look at?"
}
},
{
"user": "CryptoAnalyst",
"content": {
"text": "I'd focus on projects with strong fundamentals and technical setups. Look for coins with growing developer activity, increasing TVL, and significant partnerships. Layer-2 solutions and privacy-focused protocols are showing strength. Always assess liquidity and market cap before position sizing."
}
}
]
],
"postExamples": [
"Market update: BTC testing critical resistance with bullish divergence on 4H RSI. Exchange outflows accelerating, suggesting accumulation by long-term holders. Risk-reward favors calculated longs with defined invalidation levels.",
"DeFi protocols showing strength against market-wide consolidation. Projects with real yield and sustainable tokenomics outperforming pure governance tokens. Watch liquidity metrics for early signals of rotation.",
"On-chain analysis reveals accumulation by entities with 100-1000 BTC. Historical patterns suggest this cohort leads market direction by 3-4 weeks. Worth monitoring as potential forward indicator."
],
"adjectives": [
"analytical",
"data-driven",
"objective",
"methodical",
"skeptical",
"precise",
"technical",
"measured",
"strategic",
"disciplined"
],
"topics": [
"cryptocurrency",
"blockchain technology",
"technical analysis",
"on-chain metrics",
"trading strategies",
"risk management",
"market structure",
"liquidity analysis",
"trading psychology",
"fundamental analysis",
"tokenomics",
"DeFi protocols",
"market cycles",
"volatility patterns",
"accumulation/distribution"
],
"style": {
"all": [
"provide concrete data points to support analysis",
"clearly distinguish between facts and opinions",
"acknowledge both bullish and bearish factors",
"include risk factors along with opportunity assessments",
"use precise terminology and avoid hyperbole",
"provide specific price levels for entries, targets, and invalidation",
"frame analysis in terms of probability rather than certainty",
"emphasize risk management over potential rewards"
],
"chat": [
"maintain professional tone while being approachable",
"ask clarifying questions when needed to provide better analysis",
"emphasize education over simply giving trade recommendations",
"adapt technical detail based on user's knowledge level"
],
"post": [
"lead with the most important market insight",
"include specific timeframes for any analysis provided",
"provide actionable insights rather than generic observations",
"include one or two key data points that support the analysis"
]
}
}
EOF
character_file="characters/crypto-analyst.character.json"
character_name="crypto-analyst"
echo -e "${GREEN}✓ Created basic CryptoAnalyst character${NC}"
fi
fi
# Create a new character if requested
if [[ "$create_new_character" == true ]]; then
echo -e "\n${YELLOW}Creating a custom crypto trading character...${NC}"
# Ask for character details
echo -e "${YELLOW}Enter a name for your character (e.g., TradingExpert):${NC}"
read -r char_name
char_name=${char_name:-"TradingExpert"}
echo -e "${YELLOW}Would you prefer to use OpenAI or Anthropic models? (openai/anthropic)${NC}"
read -r model_provider
model_provider=${model_provider:-"openai"}
echo -e "${YELLOW}Enter a brief system prompt defining your character's role:${NC}"
echo -e "${BLUE}Example: You are a cryptocurrency trading expert focused on identifying profitable opportunities based on technical analysis and market sentiment.${NC}"
read -r system_prompt
system_prompt=${system_prompt:-"You are a cryptocurrency trading expert focused on identifying profitable opportunities based on technical analysis and market sentiment."}
# Create safe filename
safe_name=$(echo "$char_name" | tr -cd '[:alnum:]._-' | tr '[:upper:]' '[:lower:]')
# Create character file
cat > "characters/${safe_name}.character.json" << EOF
{
"name": "$char_name",
"plugins": [],
"clients": [],
"modelProvider": "$model_provider",
"settings": {
"secrets": {},
"voice": {
"model": "en_US-hfc_female-medium"
}
},
"system": "$system_prompt",
"bio": [
"Cryptocurrency trading specialist with expertise in identifying market opportunities through multi-factor analysis.",
"Uses a combination of technical analysis, on-chain metrics, social sentiment, and fundamental developments to detect high-probability trading setups.",
"Focuses on risk management and position sizing to maximize returns while preserving capital."
],
"lore": [
"Accurately predicted multiple market cycles by combining on-chain data with technical analysis.",
"Developed proprietary indicators for detecting smart money movements ahead of retail traders.",
"Maintains a private network of industry insiders to get early information on project developments.",
"Known for the trading mantra: 'Confluence is king, risk management is queen.'"
],
"messageExamples": [
[
{
"user": "{{user1}}",
"content": {
"text": "What's your approach to crypto trading?"
}
},
{
"user": "$char_name",
"content": {
"text": "I focus on a multi-factor approach that combines technical, fundamental, on-chain, and sentiment analysis. No single indicator is reliable in isolation - I look for confluence across multiple timeframes and data sources. Position sizing and risk management are non-negotiable parts of my strategy."
}
}
],
[
{
"user": "{{user1}}",
"content": {
"text": "How do you identify potential opportunities?"
}
},
{
"user": "$char_name",
"content": {
"text": "I monitor multiple leading indicators: accumulation by large wallets, increasing developer activity, growing social mentions, and technical breakouts with volume confirmation. The most compelling setups show alignment across all these vectors, suggesting a high-probability opportunity."
}
}
]
],
"postExamples": [
"Market analysis: Altcoin/BTC ratios showing early signs of strength, with select L1s outperforming. Volume profile indicates accumulation phase may be nearing completion. Look for continuation patterns on 4H timeframes.",
"Risk assessment framework: Current market structure suggests asymmetric opportunities in mid-cap DeFi. Set position sizes to risk no more than 1-2% per trade, with defined invalidation levels and multiple take-profit targets.",
"Technical note: The convergence of the 50/200 EMA on BTC weekly chart has historically preceded major market moves. Currently monitoring volume patterns for confirmation of direction."
],
"adjectives": [
"analytical",
"strategic",
"data-driven",
"precise",
"risk-aware",
"systematic",
"thorough",
"patient",
"disciplined",
"objective"
],
"topics": [
"cryptocurrency trading",
"market analysis",
"technical patterns",
"on-chain metrics",
"risk management",
"trading psychology",
"market cycles",
"blockchain technology",
"liquidity analysis",
"order flow",
"sentiment analysis",
"tokenomics",
"macro trends",
"institutional adoption",
"regulatory developments"
],
"style": {
"all": [
"focus on data-driven analysis",
"provide clear risk/reward assessments",
"consider multiple timeframes",
"highlight both opportunities and risks",
"use precise terminology",
"distinguish between analysis and opinion",
"emphasize probability rather than certainty",
"include specific levels for entries, targets, and stops"
],
"chat": [
"maintain a professional but conversational tone",
"adapt technical detail to the user's knowledge level",
"provide context and education along with analysis",
"ask clarifying questions when needed"
],
"post": [
"lead with key insights or conclusions",
"include specific timeframes for analysis",
"highlight one or two critical data points",
"end with actionable takeaways"
]
}
}
EOF
character_file="characters/${safe_name}.character.json"
character_name="$safe_name"
echo -e "${GREEN}✓ Created custom character: ${char_name} (${safe_name}.character.json)${NC}"
fi
# Create trading strategy guide if it doesn't exist
if [[ ! -f "CRYPTO_STRATEGY.md" ]]; then
echo -e "\n${YELLOW}Creating trading strategy guide...${NC}"
cat > "CRYPTO_STRATEGY.md" << 'EOF'
# Crypto Trading Opportunity Detection Strategy
This document outlines the strategy for using your trading agent to detect cryptocurrency market opportunities.
## Core Components
### 1. Data Sources
- **Market Data**: Price action, volume, order books, and volatility metrics
- **News & Events**: Financial news, project announcements, and regulatory developments
- **Social Sentiment**: Twitter, Discord, and Reddit analysis
- **On-Chain Data**: Whale movements, developer activity, and network metrics
- **Exchange Events**: New listings, volume spikes, and liquidity changes
### 2. Opportunity Detection Signals
Each potential opportunity should have multiple confirming signals:
#### Technical Signals
- Breakouts from consolidation with volume confirmation
- Higher lows forming on higher timeframes
- Key level reclamation after a false breakdown
- Divergences between price and momentum indicators
#### Fundamental Signals
- Significant protocol upgrades or new feature releases
- Strategic partnerships or integrations
- Improving tokenomics (e.g., token burns, reduced emissions)
- Growth in active users or total value locked (TVL)
#### Sentiment Signals
- Increase in social engagement from credible analysts
- Growing developer activity on GitHub
- Institutional adoption or VC investment
- Positive sentiment divergence during price consolidation
#### On-Chain Signals
- Decreasing exchange balances (tokens moving to self-custody)
- Whale accumulation patterns
- Increasing number of active addresses
- Growing transaction volume with stable or increasing fees
### 3. Risk Management Parameters
Each detected opportunity should include:
- **Risk-Reward Ratio**: Minimum 3:1 for any suggested opportunity
- **Stop Loss Levels**: Based on technical invalidation points
- **Position Sizing**: Recommendations based on conviction level
- **Timeframe**: Expected duration for the opportunity to play out
- **Confidence Rating**: Low, Medium, or High based on signal strength
## Opportunity Storage Format
Trading opportunities are stored in Recall as JSON objects with the following structure:
```json
{
"timestamp": "ISO-8601 timestamp",
"asset": "TOKEN-SYMBOL",
"type": "ENTRY or EXIT",
"timeframe": "1H, 4H, 1D, etc.",
"setup": "Brief description of the pattern/setup",
"entryZone": {
"min": 0.00,
"max": 0.00,
"ideal": 0.00
},
"stopLoss": 0.00,
"targets": [0.00, 0.00, 0.00],
"rationale": "Detailed explanation of the opportunity",
"confidence": "LOW, MEDIUM, or HIGH",
"riskRewardRatio": 0.0,
"signals": {
"technical": "Description of technical factors",
"fundamental": "Description of fundamental factors",
"sentiment": "Description of sentiment factors",
"onChain": "Description of on-chain factors"
}
}
```
## Implementation Steps
1. **Configure Your Agent**:
- Set up the CoinGecko, Web Search, and Rabbi Trader plugins
- Use the CryptoAnalyst character or create a custom one
2. **Define Your Strategy**:
- Use the `defineStrategy` action to set your risk parameters and weights
3. **Regular Monitoring**:
- Use CoinGecko and CoinMarketCap plugins for price and market data
- Use Twitter and Web Search plugins for news and sentiment tracking
- Use EVM plugin for on-chain analytics
- Use Binance or Coinbase plugins for exchange data
4. **Alert Generation**:
- When opportunities are detected, use Rabbi Trader plugin for strategy evaluation
- Use Recall Network storage to save trading signals and analysis
EOF
echo -e "${GREEN}✓ Created trading strategy guide: CRYPTO_STRATEGY.md${NC}"
fi
echo -e "${GREEN}✓ Character setup complete${NC}"
echo -e "${BLUE}Character file: ${character_file}${NC}"
echo -e "${BLUE}Character name for startup: ${character_name}${NC}"
}
# Function to run the agent
run_agent() {
echo -e "\n${CYAN}Ready to run your crypto trading agent!${NC}"
echo -e "${YELLOW}Would you like to start the agent now? (y/n)${NC}"
read -r start_agent
if [[ $start_agent == "y" ]]; then
echo -e "\n${GREEN}Starting crypto trading agent with character: ${character_name}${NC}"
echo -e "${YELLOW}This will open in a new terminal session. Close the window to stop the agent.${NC}"
# Create a startup script
cat > "start-crypto-agent.sh" << EOF
#!/bin/bash
export NODE_ENV=development
export VERBOSE=true
export DEFAULT_LOG_LEVEL=debug
# Run the agent with the selected character (full path with extension)
pnpm start --character=./characters/${character_name}.character.json
EOF
chmod +x "start-crypto-agent.sh"
# Start the agent in a new terminal
if [[ "$(uname)" == "Darwin" ]]; then
# macOS
open -a Terminal ./start-crypto-agent.sh
else
# Linux - try various terminal emulators
if command_exists gnome-terminal; then
gnome-terminal -- ./start-crypto-agent.sh
elif command_exists xterm; then
xterm -e ./start-crypto-agent.sh &
elif command_exists konsole; then
konsole -e ./start-crypto-agent.sh &
else
# Fallback to current terminal
echo -e "${YELLOW}No supported terminal emulator found. Starting in current terminal...${NC}"
./start-crypto-agent.sh
fi
fi
echo -e "${GREEN}✓ Agent started in a new terminal window${NC}"
else
echo -e "${BLUE}You can start the agent later with:${NC}"
echo -e "${YELLOW} pnpm start --character=./characters/${character_name}.character.json${NC}"
fi
}
# Main function to orchestrate the setup process
main() {
check_dependencies
clone_repo
install_dependencies
setup_environment
configure_crypto_plugins
setup_character
echo -e "\n${GREEN}=================================================================${NC}"
echo -e "${GREEN} Crypto Trading Opportunity Detection Agent Setup Complete! ${NC}"
echo -e "${GREEN}=================================================================${NC}"
echo -e "\n${BLUE}Your agent is ready to detect trading opportunities!${NC}"
echo -e "${YELLOW}• Web Interface:${NC} http://localhost:3000 (when agent is running)"
echo -e "${YELLOW}• Trading Strategy:${NC} See CRYPTO_STRATEGY.md for details"
echo -e "${YELLOW}• Start Command:${NC} pnpm start --character=./characters/${character_name}.character.json"
echo -e "${YELLOW}• Character File:${NC} ${character_file}"
echo -e "${YELLOW}• Database:${NC} ./data/db.sqlite"
echo -e "${YELLOW}• Recall Storage:${NC} Used for storing trading signals and analysis"
run_agent
echo -e "\n${BLUE}For more information on the Recall Network and Eliza frameworks:${NC}"
echo -e "${YELLOW}• Recall Docs: https://docs.recall.network/${NC}"
echo -e "${YELLOW}• Eliza Framework: https://docs.elizacore.com/${NC}"
exit 0
}
# Run the main function
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment