claude-evolve 1.7.22 → 1.7.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/claude-evolve-ideate-py +97 -0
- package/lib/ideation_helper.py +745 -0
- package/package.json +2 -1
- package/bin/claude-evolve-ideate.debug +0 -907
|
@@ -1,907 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
set -e
|
|
4
|
-
|
|
5
|
-
# Load configuration
|
|
6
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
7
|
-
# shellcheck source=../lib/config.sh
|
|
8
|
-
source "$SCRIPT_DIR/../lib/config.sh"
|
|
9
|
-
|
|
10
|
-
# Use CLAUDE_EVOLVE_CONFIG if set, otherwise default
|
|
11
|
-
if [[ -n ${CLAUDE_EVOLVE_CONFIG:-} ]]; then
|
|
12
|
-
load_config "$CLAUDE_EVOLVE_CONFIG"
|
|
13
|
-
else
|
|
14
|
-
load_config
|
|
15
|
-
fi
|
|
16
|
-
|
|
17
|
-
# Function to determine which model to use based on generation
|
|
18
|
-
get_model_for_generation() {
|
|
19
|
-
local generation="$1"
|
|
20
|
-
local gen_num
|
|
21
|
-
|
|
22
|
-
# Extract numeric part of generation (e.g., "05" from gen05)
|
|
23
|
-
if [[ $generation =~ ^0*([0-9]+)$ ]]; then
|
|
24
|
-
gen_num=$((10#${BASH_REMATCH[1]}))
|
|
25
|
-
else
|
|
26
|
-
gen_num=1 # Default for malformed input
|
|
27
|
-
fi
|
|
28
|
-
|
|
29
|
-
# Check which AI tools are available
|
|
30
|
-
local has_o3=false
|
|
31
|
-
local has_gemini=false
|
|
32
|
-
|
|
33
|
-
if command -v codex >/dev/null 2>&1; then
|
|
34
|
-
has_o3=true
|
|
35
|
-
fi
|
|
36
|
-
|
|
37
|
-
if command -v gemini >/dev/null 2>&1; then
|
|
38
|
-
has_gemini=true
|
|
39
|
-
fi
|
|
40
|
-
|
|
41
|
-
# Determine rotation based on what's available
|
|
42
|
-
if [[ "$has_o3" == "true" && "$has_gemini" == "true" ]]; then
|
|
43
|
-
# All three available: opus -> o3 -> gemini rotation
|
|
44
|
-
case $((gen_num % 3)) in
|
|
45
|
-
1) echo "opus" ;; # 1, 4, 7, 10...
|
|
46
|
-
2) echo "o3" ;; # 2, 5, 8, 11...
|
|
47
|
-
0) echo "gemini" ;; # 3, 6, 9, 12...
|
|
48
|
-
esac
|
|
49
|
-
elif [[ "$has_o3" == "true" ]]; then
|
|
50
|
-
# Only opus and o3: alternate between them
|
|
51
|
-
if (( gen_num % 2 == 1 )); then
|
|
52
|
-
echo "opus" # Odd generations
|
|
53
|
-
else
|
|
54
|
-
echo "o3" # Even generations
|
|
55
|
-
fi
|
|
56
|
-
elif [[ "$has_gemini" == "true" ]]; then
|
|
57
|
-
# Only opus and gemini: alternate between them
|
|
58
|
-
if (( gen_num % 2 == 1 )); then
|
|
59
|
-
echo "opus" # Odd generations
|
|
60
|
-
else
|
|
61
|
-
echo "gemini" # Even generations
|
|
62
|
-
fi
|
|
63
|
-
else
|
|
64
|
-
# Only opus available
|
|
65
|
-
echo "opus"
|
|
66
|
-
fi
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
# Helper function to call AI model (alternating based on generation)
|
|
70
|
-
call_ai_with_limit_check() {
|
|
71
|
-
local prompt="$1"
|
|
72
|
-
local generation="${2:-01}" # Default to generation 01 if not provided
|
|
73
|
-
|
|
74
|
-
# Determine which model to use for this generation
|
|
75
|
-
local preferred_model
|
|
76
|
-
preferred_model=$(get_model_for_generation "$generation")
|
|
77
|
-
|
|
78
|
-
echo "[INFO] Generation $generation: Using $preferred_model" >&2
|
|
79
|
-
|
|
80
|
-
# Try preferred model first
|
|
81
|
-
if [[ "$preferred_model" == "o3" ]] && command -v codex >/dev/null 2>&1; then
|
|
82
|
-
echo "[INFO] Using codex o3 for ideation" >&2
|
|
83
|
-
|
|
84
|
-
# Call codex with o3 model using -q flag and --full-auto
|
|
85
|
-
local ai_output
|
|
86
|
-
ai_output=$(codex -m o3 --full-auto -q "$prompt" 2>&1)
|
|
87
|
-
local ai_exit_code=$?
|
|
88
|
-
|
|
89
|
-
if [[ $ai_exit_code -eq 0 ]]; then
|
|
90
|
-
# Clean o3 output - it may be JSON with the response in a field
|
|
91
|
-
local cleaned_output
|
|
92
|
-
# Try to extract content from JSON response if present
|
|
93
|
-
if echo "$ai_output" | grep -q '"content"'; then
|
|
94
|
-
# Attempt to extract content field from JSON
|
|
95
|
-
cleaned_output=$(echo "$ai_output" | python3 -c "
|
|
96
|
-
import sys
|
|
97
|
-
import json
|
|
98
|
-
try:
|
|
99
|
-
data = json.load(sys.stdin)
|
|
100
|
-
if 'content' in data:
|
|
101
|
-
print(data['content'])
|
|
102
|
-
elif 'response' in data:
|
|
103
|
-
print(data['response'])
|
|
104
|
-
elif 'text' in data:
|
|
105
|
-
print(data['text'])
|
|
106
|
-
else:
|
|
107
|
-
# If no known field, print the whole thing
|
|
108
|
-
print(json.dumps(data))
|
|
109
|
-
except:
|
|
110
|
-
# If not valid JSON, print as-is
|
|
111
|
-
print(sys.stdin.read())
|
|
112
|
-
" 2>/dev/null || echo "$ai_output")
|
|
113
|
-
else
|
|
114
|
-
cleaned_output="$ai_output"
|
|
115
|
-
fi
|
|
116
|
-
|
|
117
|
-
# Validate the output is not empty and doesn't contain error messages
|
|
118
|
-
if [[ -n "$cleaned_output" ]] && ! echo "$cleaned_output" | grep -q "error\|failed\|exception"; then
|
|
119
|
-
echo "$cleaned_output"
|
|
120
|
-
return 0
|
|
121
|
-
else
|
|
122
|
-
echo "[WARN] Codex o3 returned invalid output, falling back to Claude Opus" >&2
|
|
123
|
-
preferred_model="opus"
|
|
124
|
-
fi
|
|
125
|
-
else
|
|
126
|
-
echo "[WARN] Codex o3 failed with exit code $ai_exit_code, falling back to Claude Opus" >&2
|
|
127
|
-
preferred_model="opus"
|
|
128
|
-
fi
|
|
129
|
-
elif [[ "$preferred_model" == "gemini" ]] && command -v gemini >/dev/null 2>&1; then
|
|
130
|
-
echo "[INFO] Using gemini 2.5 pro for ideation" >&2
|
|
131
|
-
|
|
132
|
-
# Call gemini with -y and -p flags
|
|
133
|
-
local ai_output
|
|
134
|
-
ai_output=$(gemini -y -p "$prompt" 2>&1)
|
|
135
|
-
local ai_exit_code=$?
|
|
136
|
-
|
|
137
|
-
if [[ $ai_exit_code -eq 0 ]]; then
|
|
138
|
-
# Check for authentication messages or other non-response content
|
|
139
|
-
if echo "$ai_output" | grep -q "Attempting to authenticate\|Authenticating\|Loading\|Initializing"; then
|
|
140
|
-
echo "[WARN] Gemini is still authenticating, falling back to Claude Opus" >&2
|
|
141
|
-
preferred_model="opus"
|
|
142
|
-
elif [[ -z "$ai_output" ]] || [[ $(echo "$ai_output" | wc -l) -lt 2 ]]; then
|
|
143
|
-
echo "[WARN] Gemini returned insufficient output, falling back to Claude Opus" >&2
|
|
144
|
-
preferred_model="opus"
|
|
145
|
-
else
|
|
146
|
-
echo "$ai_output"
|
|
147
|
-
return 0
|
|
148
|
-
fi
|
|
149
|
-
else
|
|
150
|
-
echo "[WARN] Gemini failed with exit code $ai_exit_code, falling back to Claude Opus" >&2
|
|
151
|
-
preferred_model="opus"
|
|
152
|
-
fi
|
|
153
|
-
fi
|
|
154
|
-
|
|
155
|
-
# Use Claude with preferred model (or fallback)
|
|
156
|
-
echo "[INFO] Using Claude $preferred_model for ideation" >&2
|
|
157
|
-
|
|
158
|
-
# Call Claude and capture output
|
|
159
|
-
local claude_output
|
|
160
|
-
claude_output=$(echo "$prompt" | claude --dangerously-skip-permissions --model "$preferred_model" -p 2>&1)
|
|
161
|
-
local claude_exit_code=$?
|
|
162
|
-
|
|
163
|
-
# Check for usage limit
|
|
164
|
-
if echo "$claude_output" | grep -q "Claude AI usage limit reached"; then
|
|
165
|
-
# Extract timestamp if available
|
|
166
|
-
local limit_timestamp=$(echo "$claude_output" | grep -o "Claude AI usage limit reached|[0-9]*" | cut -d'|' -f2)
|
|
167
|
-
|
|
168
|
-
# Print red error message
|
|
169
|
-
echo -e "\033[31m[ERROR] CLAUDE AI USAGE LIMIT REACHED!\033[0m" >&2
|
|
170
|
-
echo -e "\033[31m[ERROR] Ideation halted due to API rate limits.\033[0m" >&2
|
|
171
|
-
|
|
172
|
-
if [[ -n $limit_timestamp ]]; then
|
|
173
|
-
# Convert timestamp to human-readable format
|
|
174
|
-
local limit_date=$(date -r "$limit_timestamp" "+%Y-%m-%d %H:%M:%S" 2>/dev/null || echo "Unknown time")
|
|
175
|
-
echo -e "\033[31m[ERROR] Limit will be released at: $limit_date\033[0m" >&2
|
|
176
|
-
fi
|
|
177
|
-
|
|
178
|
-
echo -e "\033[33m[INFO] Please wait for the rate limit to reset before continuing.\033[0m" >&2
|
|
179
|
-
echo -e "\033[33m[INFO] No ideas were generated. Run ideate again when the limit resets.\033[0m" >&2
|
|
180
|
-
|
|
181
|
-
exit 1
|
|
182
|
-
fi
|
|
183
|
-
|
|
184
|
-
# Validate output doesn't contain shell constructs that could corrupt CSV
|
|
185
|
-
if echo "$claude_output" | grep -E "EOF.*<.*null|<<.*EOF|<.*dev.*null" >/dev/null 2>&1; then
|
|
186
|
-
echo "[ERROR] AI output contains invalid shell constructs" >&2
|
|
187
|
-
echo "[DEBUG] Problematic output: $claude_output" | head -5 >&2
|
|
188
|
-
return 1
|
|
189
|
-
fi
|
|
190
|
-
|
|
191
|
-
# Output Claude's response
|
|
192
|
-
echo "$claude_output"
|
|
193
|
-
|
|
194
|
-
return $claude_exit_code
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
# Backward compatibility alias
|
|
198
|
-
call_claude_with_limit_check() {
|
|
199
|
-
call_ai_with_limit_check "$@"
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
# Parse arguments
|
|
203
|
-
use_strategies=true
|
|
204
|
-
|
|
205
|
-
while [[ $# -gt 0 ]]; do
|
|
206
|
-
case $1 in
|
|
207
|
-
--help)
|
|
208
|
-
cat <<EOF
|
|
209
|
-
claude-evolve ideate - Generate new algorithm ideas using evolutionary strategies
|
|
210
|
-
|
|
211
|
-
USAGE:
|
|
212
|
-
claude-evolve ideate [--legacy N]
|
|
213
|
-
|
|
214
|
-
OPTIONS:
|
|
215
|
-
--legacy N Use legacy mode with N ideas (ignores strategy config)
|
|
216
|
-
--help Show this help message
|
|
217
|
-
|
|
218
|
-
DESCRIPTION:
|
|
219
|
-
Generates algorithm ideas using multi-strategy evolutionary approach:
|
|
220
|
-
- Novel exploration: Pure creativity, global search
|
|
221
|
-
- Hill climbing: Parameter tuning of top performers
|
|
222
|
-
- Structural mutation: Algorithmic changes to top performers
|
|
223
|
-
- Crossover hybrid: Combine successful approaches
|
|
224
|
-
|
|
225
|
-
Strategy distribution is configured in evolution/config.yaml
|
|
226
|
-
EOF
|
|
227
|
-
exit 0
|
|
228
|
-
;;
|
|
229
|
-
--legacy)
|
|
230
|
-
use_strategies=false
|
|
231
|
-
shift
|
|
232
|
-
if [[ $1 =~ ^[0-9]+$ ]]; then
|
|
233
|
-
TOTAL_IDEAS=$1
|
|
234
|
-
shift
|
|
235
|
-
else
|
|
236
|
-
echo "[ERROR] --legacy requires a number" >&2
|
|
237
|
-
exit 1
|
|
238
|
-
fi
|
|
239
|
-
;;
|
|
240
|
-
*)
|
|
241
|
-
echo "[ERROR] Unknown option: $1" >&2
|
|
242
|
-
exit 1
|
|
243
|
-
;;
|
|
244
|
-
esac
|
|
245
|
-
done
|
|
246
|
-
|
|
247
|
-
# Check workspace using config
|
|
248
|
-
if [[ ! -d "$FULL_EVOLUTION_DIR" ]]; then
|
|
249
|
-
echo "[ERROR] Evolution workspace not found: $FULL_EVOLUTION_DIR. Run 'claude-evolve setup' first." >&2
|
|
250
|
-
exit 1
|
|
251
|
-
fi
|
|
252
|
-
|
|
253
|
-
# Ensure CSV exists
|
|
254
|
-
if [[ ! -f "$FULL_CSV_PATH" ]]; then
|
|
255
|
-
echo "id,basedOnId,description,performance,status" >"$FULL_CSV_PATH"
|
|
256
|
-
fi
|
|
257
|
-
|
|
258
|
-
# Validate strategy configuration
|
|
259
|
-
if [[ $use_strategies == true ]]; then
|
|
260
|
-
total_check=$((NOVEL_EXPLORATION + HILL_CLIMBING + STRUCTURAL_MUTATION + CROSSOVER_HYBRID))
|
|
261
|
-
if [[ $total_check -ne $TOTAL_IDEAS ]]; then
|
|
262
|
-
echo "[ERROR] Strategy counts don't sum to total_ideas ($total_check != $TOTAL_IDEAS)" >&2
|
|
263
|
-
echo "Check your evolution/config.yaml configuration" >&2
|
|
264
|
-
exit 1
|
|
265
|
-
fi
|
|
266
|
-
fi
|
|
267
|
-
|
|
268
|
-
# Get next generation number
|
|
269
|
-
get_next_generation() {
|
|
270
|
-
if [[ ! -f "$FULL_CSV_PATH" ]]; then
|
|
271
|
-
echo "01"
|
|
272
|
-
return
|
|
273
|
-
fi
|
|
274
|
-
|
|
275
|
-
# Use Python for proper CSV parsing
|
|
276
|
-
local max_gen
|
|
277
|
-
max_gen=$("$PYTHON_CMD" -c "
|
|
278
|
-
import csv
|
|
279
|
-
max_gen = 0
|
|
280
|
-
with open('$FULL_CSV_PATH', 'r') as f:
|
|
281
|
-
reader = csv.reader(f)
|
|
282
|
-
next(reader, None) # Skip header
|
|
283
|
-
for row in reader:
|
|
284
|
-
if row and len(row) > 0:
|
|
285
|
-
id_field = row[0].strip()
|
|
286
|
-
if id_field.startswith('gen') and '-' in id_field:
|
|
287
|
-
try:
|
|
288
|
-
gen_part = id_field.split('-')[0] # e.g., 'gen01'
|
|
289
|
-
gen_num = int(gen_part[3:]) # Extract number after 'gen'
|
|
290
|
-
max_gen = max(max_gen, gen_num)
|
|
291
|
-
except (ValueError, IndexError):
|
|
292
|
-
pass
|
|
293
|
-
print(max_gen)
|
|
294
|
-
")
|
|
295
|
-
|
|
296
|
-
# Increment and format with leading zero
|
|
297
|
-
printf "%02d" $((max_gen + 1))
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
# Get next available ID number for current generation
|
|
301
|
-
get_next_id_number() {
|
|
302
|
-
"$PYTHON_CMD" -c "
|
|
303
|
-
import csv
|
|
304
|
-
import re
|
|
305
|
-
max_id = 0
|
|
306
|
-
pattern = re.compile(r'^gen$CURRENT_GENERATION-(\d+)$')
|
|
307
|
-
with open('$FULL_CSV_PATH', 'r') as f:
|
|
308
|
-
reader = csv.reader(f)
|
|
309
|
-
next(reader, None) # Skip header
|
|
310
|
-
for row in reader:
|
|
311
|
-
if row and len(row) > 0:
|
|
312
|
-
match = pattern.match(row[0].strip())
|
|
313
|
-
if match:
|
|
314
|
-
max_id = max(max_id, int(match.group(1)))
|
|
315
|
-
print(max_id + 1)
|
|
316
|
-
"
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
# Process AI output and add ideas to CSV
|
|
320
|
-
process_ai_ideas() {
|
|
321
|
-
local ai_output="$1"
|
|
322
|
-
local count="$2"
|
|
323
|
-
local idea_type="$3" # novel, hill-climbing, structural, crossover
|
|
324
|
-
local top_performers="${4:-}" # Optional, for non-novel ideas
|
|
325
|
-
|
|
326
|
-
local next_id_num=$(get_next_id_number)
|
|
327
|
-
local ideas_added=0
|
|
328
|
-
|
|
329
|
-
while IFS= read -r line && [[ $ideas_added -lt $count ]]; do
|
|
330
|
-
# Skip empty lines
|
|
331
|
-
[[ -z "$line" || "$line" =~ ^[[:space:]]*$ ]] && continue
|
|
332
|
-
|
|
333
|
-
# Skip lines that look like headers or metadata
|
|
334
|
-
[[ "$line" =~ ^#|^\[|^==|^-- ]] && continue
|
|
335
|
-
|
|
336
|
-
# Clean the line
|
|
337
|
-
line=$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
338
|
-
line=$(echo "$line" | sed 's/^[0-9]\+\.\?[[:space:]]*//') # Remove numbering
|
|
339
|
-
line=$(echo "$line" | sed 's/^-[[:space:]]*//') # Remove bullet points
|
|
340
|
-
|
|
341
|
-
# Extract parent ID and description based on type
|
|
342
|
-
local parent_id=""
|
|
343
|
-
local description="$line"
|
|
344
|
-
|
|
345
|
-
if [[ "$idea_type" != "novel" ]]; then
|
|
346
|
-
# For non-novel ideas, extract parent ID from "From X:" format
|
|
347
|
-
if [[ "$line" =~ ^From[[:space:]]+([^:]+):[[:space:]]*(.+)$ ]]; then
|
|
348
|
-
parent_id="${BASH_REMATCH[1]}"
|
|
349
|
-
description="${BASH_REMATCH[2]}"
|
|
350
|
-
else
|
|
351
|
-
# If no parent specified, use the first from top_performers
|
|
352
|
-
parent_id=$(echo "$top_performers" | head -1 | cut -d',' -f1)
|
|
353
|
-
fi
|
|
354
|
-
fi
|
|
355
|
-
|
|
356
|
-
# Skip if description is too short or contains problematic content
|
|
357
|
-
[[ ${#description} -lt 20 ]] && continue
|
|
358
|
-
if echo "$description" | grep -qE 'EOF|/dev/null|<<<|>>>'; then
|
|
359
|
-
continue
|
|
360
|
-
fi
|
|
361
|
-
|
|
362
|
-
# Skip AI system messages and errors
|
|
363
|
-
if echo "$description" | grep -qiE 'loaded.*cached.*credentials|authenticating|loading.*model|initializing|error.*occurred|failed.*to.*load|api.*key|rate.*limit|connection.*error|timeout|please.*try.*again|authentication.*failed|invalid.*request|model.*not.*available'; then
|
|
364
|
-
echo "[WARN] Skipping AI system message: $description" >&2
|
|
365
|
-
continue
|
|
366
|
-
fi
|
|
367
|
-
|
|
368
|
-
# Skip responses that don't look like algorithm descriptions
|
|
369
|
-
if ! echo "$description" | grep -qiE 'algorithm|strategy|trading|position|signal|indicator|portfolio|risk|stop.?loss|profit|market|price|volatility|momentum|trend|regime|filter|threshold|window|period|weight|allocation|component'; then
|
|
370
|
-
echo "[WARN] Skipping non-algorithm description: $description" >&2
|
|
371
|
-
continue
|
|
372
|
-
fi
|
|
373
|
-
|
|
374
|
-
# Generate ID for this idea
|
|
375
|
-
local idea_id=$(printf "gen%s-%03d" "$CURRENT_GENERATION" $((next_id_num + ideas_added)))
|
|
376
|
-
|
|
377
|
-
# Escape quotes in description for CSV
|
|
378
|
-
description="${description//\"/\"\"}"
|
|
379
|
-
|
|
380
|
-
# Append to CSV
|
|
381
|
-
echo "$idea_id,$parent_id,\"$description\",,pending" >> "$FULL_CSV_PATH"
|
|
382
|
-
|
|
383
|
-
((ideas_added++))
|
|
384
|
-
if [[ -n "$parent_id" ]]; then
|
|
385
|
-
echo "[INFO] Added $idea_type idea $idea_id (parent: $parent_id): ${description:0:50}..."
|
|
386
|
-
else
|
|
387
|
-
echo "[INFO] Added $idea_type idea $idea_id: ${description:0:70}..."
|
|
388
|
-
fi
|
|
389
|
-
done <<< "$ai_output"
|
|
390
|
-
|
|
391
|
-
if [[ $ideas_added -lt $count ]]; then
|
|
392
|
-
echo "[WARN] Only generated $ideas_added out of $count requested $idea_type ideas" >&2
|
|
393
|
-
fi
|
|
394
|
-
|
|
395
|
-
# Return error if no valid ideas were generated
|
|
396
|
-
if [[ $ideas_added -eq 0 ]]; then
|
|
397
|
-
echo "[ERROR] Failed to generate any valid $idea_type ideas - AI may be returning system messages" >&2
|
|
398
|
-
return 1
|
|
399
|
-
fi
|
|
400
|
-
|
|
401
|
-
return 0
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
# Get next available ID for current generation
|
|
405
|
-
get_next_id() {
|
|
406
|
-
local generation="$1"
|
|
407
|
-
if [[ ! -f "$FULL_CSV_PATH" ]]; then
|
|
408
|
-
echo "gen${generation}-001"
|
|
409
|
-
return
|
|
410
|
-
fi
|
|
411
|
-
|
|
412
|
-
# Use Python for proper CSV parsing
|
|
413
|
-
local max_id
|
|
414
|
-
max_id=$("$PYTHON_CMD" -c "
|
|
415
|
-
import csv
|
|
416
|
-
import re
|
|
417
|
-
max_id = 0
|
|
418
|
-
pattern = re.compile(r'^gen${generation}-(\d+)$')
|
|
419
|
-
with open('$FULL_CSV_PATH', 'r') as f:
|
|
420
|
-
reader = csv.reader(f)
|
|
421
|
-
next(reader, None) # Skip header
|
|
422
|
-
for row in reader:
|
|
423
|
-
if row and len(row) > 0:
|
|
424
|
-
id_field = row[0].strip()
|
|
425
|
-
match = pattern.match(id_field)
|
|
426
|
-
if match:
|
|
427
|
-
id_num = int(match.group(1))
|
|
428
|
-
max_id = max(max_id, id_num)
|
|
429
|
-
print(max_id)
|
|
430
|
-
")
|
|
431
|
-
|
|
432
|
-
# Format next ID with generation and 3-digit number
|
|
433
|
-
printf "gen%s-%03d" "$generation" $((max_id + 1))
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
# Get top performers for parent selection (absolute + top novel candidates)
|
|
438
|
-
get_top_performers() {
|
|
439
|
-
local num_requested="$1"
|
|
440
|
-
if [[ ! -f "$FULL_CSV_PATH" ]]; then
|
|
441
|
-
echo ""
|
|
442
|
-
return
|
|
443
|
-
fi
|
|
444
|
-
|
|
445
|
-
# Use Python to properly parse CSV and find top performers + top novel candidates
|
|
446
|
-
"$PYTHON_CMD" -c "
|
|
447
|
-
import csv
|
|
448
|
-
import sys
|
|
449
|
-
|
|
450
|
-
with open('$FULL_CSV_PATH', 'r') as f:
|
|
451
|
-
reader = csv.reader(f)
|
|
452
|
-
next(reader) # Skip header
|
|
453
|
-
|
|
454
|
-
completed = []
|
|
455
|
-
novel = []
|
|
456
|
-
|
|
457
|
-
# Collect all completed candidates
|
|
458
|
-
for row in reader:
|
|
459
|
-
if len(row) >= 5 and row[3] and row[4] == 'complete':
|
|
460
|
-
try:
|
|
461
|
-
candidate_id = row[0]
|
|
462
|
-
parent_id = row[1] if len(row) > 1 else ''
|
|
463
|
-
description = row[2] if len(row) > 2 else ''
|
|
464
|
-
score = float(row[3])
|
|
465
|
-
|
|
466
|
-
completed.append((candidate_id, description, score))
|
|
467
|
-
|
|
468
|
-
# Track novel candidates separately
|
|
469
|
-
if not parent_id:
|
|
470
|
-
novel.append((candidate_id, description, score))
|
|
471
|
-
|
|
472
|
-
except ValueError:
|
|
473
|
-
pass
|
|
474
|
-
|
|
475
|
-
# Sort absolute leaders by score (descending)
|
|
476
|
-
completed.sort(key=lambda x: x[2], reverse=True)
|
|
477
|
-
|
|
478
|
-
# Sort novel candidates by score (descending)
|
|
479
|
-
novel.sort(key=lambda x: x[2], reverse=True)
|
|
480
|
-
|
|
481
|
-
# Collect top performers
|
|
482
|
-
selected_ids = set()
|
|
483
|
-
results = []
|
|
484
|
-
|
|
485
|
-
# Add top absolute performers
|
|
486
|
-
for i, (candidate_id, description, score) in enumerate(completed[:$num_requested]):
|
|
487
|
-
results.append(f'{candidate_id},{description},{score}')
|
|
488
|
-
selected_ids.add(candidate_id)
|
|
489
|
-
|
|
490
|
-
# Add top novel candidates (if not already selected)
|
|
491
|
-
novel_count = 0
|
|
492
|
-
for candidate_id, description, score in novel:
|
|
493
|
-
if candidate_id not in selected_ids and novel_count < $NUM_REVOLUTION:
|
|
494
|
-
results.append(f'{candidate_id},{description},{score}')
|
|
495
|
-
selected_ids.add(candidate_id)
|
|
496
|
-
novel_count += 1
|
|
497
|
-
|
|
498
|
-
# Output all selected candidates
|
|
499
|
-
for result in results:
|
|
500
|
-
print(result)
|
|
501
|
-
"
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
# Generate ideas using AI with multi-strategy approach
|
|
507
|
-
ideate_ai_strategies() {
|
|
508
|
-
if [[ ! -f "$FULL_BRIEF_PATH" ]]; then
|
|
509
|
-
echo "[ERROR] $BRIEF_FILE not found. Run 'claude-evolve setup' first." >&2
|
|
510
|
-
exit 1
|
|
511
|
-
fi
|
|
512
|
-
|
|
513
|
-
# Baseline should already be evaluated by run command
|
|
514
|
-
|
|
515
|
-
# Get top performers (now includes top novel candidates)
|
|
516
|
-
local top_performers
|
|
517
|
-
top_performers=$(get_top_performers "$NUM_ELITES")
|
|
518
|
-
|
|
519
|
-
if [[ -z $top_performers ]]; then
|
|
520
|
-
echo "[INFO] No completed algorithms found, will use baseline algorithm for hill climbing"
|
|
521
|
-
# For hill climbing and mutations, use the baseline algorithm
|
|
522
|
-
top_performers="Baseline Algorithm (algorithm.py): The original algorithm provided"
|
|
523
|
-
fi
|
|
524
|
-
|
|
525
|
-
echo "[INFO] Generating $TOTAL_IDEAS ideas using multi-strategy approach:"
|
|
526
|
-
echo " Novel exploration: $NOVEL_EXPLORATION"
|
|
527
|
-
echo " Hill climbing: $HILL_CLIMBING"
|
|
528
|
-
echo " Structural mutation: $STRUCTURAL_MUTATION"
|
|
529
|
-
echo " Crossover hybrid: $CROSSOVER_HYBRID"
|
|
530
|
-
|
|
531
|
-
# Generate each type of idea by having Claude directly edit the CSV
|
|
532
|
-
[[ $NOVEL_EXPLORATION -gt 0 ]] && generate_novel_ideas_direct "$NOVEL_EXPLORATION"
|
|
533
|
-
[[ $HILL_CLIMBING -gt 0 ]] && generate_hill_climbing_direct "$HILL_CLIMBING" "$top_performers"
|
|
534
|
-
[[ $STRUCTURAL_MUTATION -gt 0 ]] && generate_structural_mutation_direct "$STRUCTURAL_MUTATION" "$top_performers"
|
|
535
|
-
[[ $CROSSOVER_HYBRID -gt 0 ]] && generate_crossover_direct "$CROSSOVER_HYBRID" "$top_performers"
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
# Generate novel exploration ideas using structured output
|
|
539
|
-
generate_novel_ideas_direct() {
|
|
540
|
-
local count="$1"
|
|
541
|
-
|
|
542
|
-
# Get next available ID for this generation
|
|
543
|
-
local next_id_num
|
|
544
|
-
next_id_num=$("$PYTHON_CMD" -c "
|
|
545
|
-
import csv
|
|
546
|
-
import re
|
|
547
|
-
max_id = 0
|
|
548
|
-
pattern = re.compile(r'^gen$CURRENT_GENERATION-(\d+)$')
|
|
549
|
-
with open('$FULL_CSV_PATH', 'r') as f:
|
|
550
|
-
reader = csv.reader(f)
|
|
551
|
-
next(reader, None) # Skip header
|
|
552
|
-
for row in reader:
|
|
553
|
-
if row and len(row) > 0:
|
|
554
|
-
match = pattern.match(row[0].strip())
|
|
555
|
-
if match:
|
|
556
|
-
max_id = max(max_id, int(match.group(1)))
|
|
557
|
-
print(max_id + 1)
|
|
558
|
-
")
|
|
559
|
-
|
|
560
|
-
local prompt="Generate exactly $count novel algorithmic ideas for trading algorithm evolution.
|
|
561
|
-
|
|
562
|
-
Current evolution context:
|
|
563
|
-
- Generation: $CURRENT_GENERATION
|
|
564
|
-
- Algorithm: $FULL_ALGORITHM_PATH
|
|
565
|
-
- Brief: $(head -20 "$FULL_BRIEF_PATH")
|
|
566
|
-
|
|
567
|
-
You MUST output EXACTLY $count lines, where each line is a single sentence describing a specific algorithmic change.
|
|
568
|
-
NO PREAMBLE, NO EXPLANATION, NO NUMBERING - just $count lines of algorithm descriptions.
|
|
569
|
-
|
|
570
|
-
Requirements:
|
|
571
|
-
- Each line should be one clear sentence describing a novel algorithmic approach
|
|
572
|
-
- Focus on creative, ambitious ideas that haven't been tried yet
|
|
573
|
-
- Consider machine learning, new indicators, regime detection, risk management, etc.
|
|
574
|
-
|
|
575
|
-
Example output format:
|
|
576
|
-
Train LSTM network on 30-day OHLCV sequences to predict next-day direction probability
|
|
577
|
-
Add cross-correlation filter that reduces positions when correlation with market breaks down
|
|
578
|
-
Implement intraday momentum using 30-minute data to adjust daily position sizes
|
|
579
|
-
|
|
580
|
-
Output exactly $count lines now:"
|
|
581
|
-
|
|
582
|
-
echo "[INFO] Generating $count novel exploration ideas..."
|
|
583
|
-
|
|
584
|
-
# Get AI response
|
|
585
|
-
local ai_output
|
|
586
|
-
local ai_error
|
|
587
|
-
if ! ai_output=$(call_ai_with_limit_check "$prompt" "$CURRENT_GENERATION" 2>&1); then
|
|
588
|
-
ai_error="$ai_output"
|
|
589
|
-
|
|
590
|
-
# Check for specific error types
|
|
591
|
-
if echo "$ai_error" | grep -qi "rate.*limit\|too.*many.*requests"; then
|
|
592
|
-
echo "[ERROR] Hit API rate limit. Please wait a moment and try again." >&2
|
|
593
|
-
elif echo "$ai_error" | grep -qi "unauthorized\|api.*key\|authentication"; then
|
|
594
|
-
# Try to identify which provider failed
|
|
595
|
-
if echo "$ai_error" | grep -qi "codex\|o3"; then
|
|
596
|
-
echo "[ERROR] Codex/O3 authentication issue. Please check your Codex API key." >&2
|
|
597
|
-
elif echo "$ai_error" | grep -qi "gemini"; then
|
|
598
|
-
echo "[ERROR] Gemini authentication issue. Please check your Gemini API key." >&2
|
|
599
|
-
elif echo "$ai_error" | grep -qi "claude\|anthropic"; then
|
|
600
|
-
echo "[ERROR] Claude authentication issue. Please check your Anthropic API key." >&2
|
|
601
|
-
else
|
|
602
|
-
echo "[ERROR] API authentication issue. Please check your API key configuration." >&2
|
|
603
|
-
echo "[ERROR] Last attempted model was from generation $CURRENT_GENERATION strategy" >&2
|
|
604
|
-
fi
|
|
605
|
-
elif echo "$ai_error" | grep -qi "timeout\|timed.*out"; then
|
|
606
|
-
echo "[ERROR] Request timed out. The prompt may be too complex." >&2
|
|
607
|
-
else
|
|
608
|
-
echo "[ERROR] AI request failed: $ai_error" >&2
|
|
609
|
-
fi
|
|
610
|
-
return 1
|
|
611
|
-
fi
|
|
612
|
-
|
|
613
|
-
# Process the output using helper function
|
|
614
|
-
process_ai_ideas "$ai_output" "$count" "novel"
|
|
615
|
-
|
|
616
|
-
echo "[INFO] Novel exploration ideas generated successfully"
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
# Generate hill climbing ideas by getting descriptions from AI
|
|
620
|
-
generate_hill_climbing_direct() {
|
|
621
|
-
local count="$1"
|
|
622
|
-
local top_performers="$2"
|
|
623
|
-
|
|
624
|
-
# Get next available ID for this generation
|
|
625
|
-
local next_id_num
|
|
626
|
-
next_id_num=$("$PYTHON_CMD" -c "
|
|
627
|
-
import csv
|
|
628
|
-
import re
|
|
629
|
-
max_id = 0
|
|
630
|
-
pattern = re.compile(r'^gen$CURRENT_GENERATION-(\d+)$')
|
|
631
|
-
with open('$FULL_CSV_PATH', 'r') as f:
|
|
632
|
-
reader = csv.reader(f)
|
|
633
|
-
next(reader, None) # Skip header
|
|
634
|
-
for row in reader:
|
|
635
|
-
if row and len(row) > 0:
|
|
636
|
-
match = pattern.match(row[0].strip())
|
|
637
|
-
if match:
|
|
638
|
-
max_id = max(max_id, int(match.group(1)))
|
|
639
|
-
print(max_id + 1)
|
|
640
|
-
")
|
|
641
|
-
|
|
642
|
-
local prompt="Generate exactly $count parameter tuning ideas for successful trading algorithms.
|
|
643
|
-
|
|
644
|
-
Successful algorithms to tune (pick one as parent):
|
|
645
|
-
$top_performers
|
|
646
|
-
|
|
647
|
-
You MUST output EXACTLY $count lines, where each line describes a parameter tuning idea.
|
|
648
|
-
NO PREAMBLE, NO EXPLANATION, NO NUMBERING - just $count lines of parameter tuning descriptions.
|
|
649
|
-
|
|
650
|
-
Each line should:
|
|
651
|
-
- Be one clear sentence about adjusting specific parameters
|
|
652
|
-
- Reference the parent algorithm ID at the beginning like \"From gen02-003:\"
|
|
653
|
-
- Focus on hyperparameters, thresholds, periods, weights, etc.
|
|
654
|
-
|
|
655
|
-
Example output format:
|
|
656
|
-
From gen02-003: Lower IBS_BUY_THRESHOLD from 0.15 to 0.12 to enter deeper oversold conditions
|
|
657
|
-
From gen02-003: Increase TRS_RSI_PERIOD from 2 to 3 for smoother RSI signals
|
|
658
|
-
From gen02-003: Raise WEIGHT_TDD from 0.38 to 0.42 to emphasize best performing strategy
|
|
659
|
-
|
|
660
|
-
Output exactly $count lines now:"
|
|
661
|
-
|
|
662
|
-
echo "[INFO] Generating $count hill climbing ideas..."
|
|
663
|
-
|
|
664
|
-
# Get AI response
|
|
665
|
-
local ai_output
|
|
666
|
-
local ai_error
|
|
667
|
-
if ! ai_output=$(call_ai_with_limit_check "$prompt" "$CURRENT_GENERATION" 2>&1); then
|
|
668
|
-
ai_error="$ai_output"
|
|
669
|
-
|
|
670
|
-
# Check for specific error types
|
|
671
|
-
if echo "$ai_error" | grep -qi "rate.*limit\|too.*many.*requests"; then
|
|
672
|
-
echo "[ERROR] Hit API rate limit. Please wait a moment and try again." >&2
|
|
673
|
-
elif echo "$ai_error" | grep -qi "unauthorized\|api.*key\|authentication"; then
|
|
674
|
-
echo "[ERROR] API authentication issue. Please check your API key." >&2
|
|
675
|
-
elif echo "$ai_error" | grep -qi "timeout\|timed.*out"; then
|
|
676
|
-
echo "[ERROR] Request timed out. The prompt may be too complex." >&2
|
|
677
|
-
elif echo "$ai_error" | grep -qi "token.*limit\|too.*long\|maximum.*length"; then
|
|
678
|
-
echo "[ERROR] Prompt exceeded token limit. Try reducing the number of top performers." >&2
|
|
679
|
-
else
|
|
680
|
-
echo "[ERROR] AI request failed: $ai_error" >&2
|
|
681
|
-
fi
|
|
682
|
-
|
|
683
|
-
echo "[INFO] Hill climbing can work with ANY completed algorithm - even baseline" >&2
|
|
684
|
-
echo "[INFO] Each algorithm has parameters that can be tuned for improvement" >&2
|
|
685
|
-
return 1
|
|
686
|
-
fi
|
|
687
|
-
|
|
688
|
-
# Process the output using helper function
|
|
689
|
-
process_ai_ideas "$ai_output" "$count" "hill-climbing" "$top_performers"
|
|
690
|
-
|
|
691
|
-
echo "[INFO] Hill climbing ideas generated successfully"
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
# Generate structural mutation ideas by getting descriptions from AI
|
|
695
|
-
generate_structural_mutation_direct() {
|
|
696
|
-
local count="$1"
|
|
697
|
-
local top_performers="$2"
|
|
698
|
-
|
|
699
|
-
local prompt="Generate exactly $count structural modification ideas for successful trading algorithms.
|
|
700
|
-
|
|
701
|
-
Successful algorithms to modify structurally:
|
|
702
|
-
$top_performers
|
|
703
|
-
|
|
704
|
-
You MUST output EXACTLY $count lines, where each line describes a structural modification idea.
|
|
705
|
-
NO PREAMBLE, NO EXPLANATION, NO NUMBERING - just $count lines of structural change descriptions.
|
|
706
|
-
|
|
707
|
-
Each line should:
|
|
708
|
-
- Be one clear sentence about architectural/structural changes
|
|
709
|
-
- Reference the parent algorithm ID at the beginning like \"From gen02-003:\"
|
|
710
|
-
- Focus on replacing components, changing architecture, adding new systems
|
|
711
|
-
|
|
712
|
-
Example output format:
|
|
713
|
-
From gen02-003: Replace 2-period RSI with LSTM-predicted momentum scores for TRS strategy
|
|
714
|
-
From gen02-003: Add ensemble voting system where sub-strategies vote on market regime
|
|
715
|
-
From gen02-003: Implement hierarchical risk budgeting with correlation-adjusted position sizing
|
|
716
|
-
|
|
717
|
-
Output exactly $count lines now:"
|
|
718
|
-
|
|
719
|
-
echo "[INFO] Generating $count structural mutation ideas..."
|
|
720
|
-
|
|
721
|
-
# Get AI response
|
|
722
|
-
local ai_output
|
|
723
|
-
local ai_error
|
|
724
|
-
if ! ai_output=$(call_ai_with_limit_check "$prompt" "$CURRENT_GENERATION" 2>&1); then
|
|
725
|
-
ai_error="$ai_output"
|
|
726
|
-
|
|
727
|
-
# Check for specific error types
|
|
728
|
-
if echo "$ai_error" | grep -qi "rate.*limit\|too.*many.*requests"; then
|
|
729
|
-
echo "[ERROR] Hit API rate limit. Please wait a moment and try again." >&2
|
|
730
|
-
elif echo "$ai_error" | grep -qi "unauthorized\|api.*key\|authentication"; then
|
|
731
|
-
# Try to identify which provider failed
|
|
732
|
-
if echo "$ai_error" | grep -qi "codex\|o3"; then
|
|
733
|
-
echo "[ERROR] Codex/O3 authentication issue. Please check your Codex API key." >&2
|
|
734
|
-
elif echo "$ai_error" | grep -qi "gemini"; then
|
|
735
|
-
echo "[ERROR] Gemini authentication issue. Please check your Gemini API key." >&2
|
|
736
|
-
elif echo "$ai_error" | grep -qi "claude\|anthropic"; then
|
|
737
|
-
echo "[ERROR] Claude authentication issue. Please check your Anthropic API key." >&2
|
|
738
|
-
else
|
|
739
|
-
echo "[ERROR] API authentication issue. Please check your API key configuration." >&2
|
|
740
|
-
echo "[ERROR] Last attempted model was from generation $CURRENT_GENERATION strategy" >&2
|
|
741
|
-
fi
|
|
742
|
-
elif echo "$ai_error" | grep -qi "timeout\|timed.*out"; then
|
|
743
|
-
echo "[ERROR] Request timed out. The prompt may be too complex." >&2
|
|
744
|
-
else
|
|
745
|
-
echo "[ERROR] AI request failed: $ai_error" >&2
|
|
746
|
-
fi
|
|
747
|
-
return 1
|
|
748
|
-
fi
|
|
749
|
-
|
|
750
|
-
# Process the output using helper function
|
|
751
|
-
process_ai_ideas "$ai_output" "$count" "structural" "$top_performers"
|
|
752
|
-
|
|
753
|
-
echo "[INFO] Structural mutation ideas generated successfully"
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
# Generate crossover hybrid ideas by getting descriptions from AI
|
|
757
|
-
generate_crossover_direct() {
|
|
758
|
-
local count="$1"
|
|
759
|
-
local top_performers="$2"
|
|
760
|
-
|
|
761
|
-
local prompt="Generate exactly $count hybrid combination ideas from successful trading algorithms.
|
|
762
|
-
|
|
763
|
-
Top performers to combine (reference at least 2 in each idea):
|
|
764
|
-
$top_performers
|
|
765
|
-
|
|
766
|
-
You MUST output EXACTLY $count lines, where each line describes a hybrid combination idea.
|
|
767
|
-
NO PREAMBLE, NO EXPLANATION, NO NUMBERING - just $count lines of hybrid combination descriptions.
|
|
768
|
-
|
|
769
|
-
Each line should:
|
|
770
|
-
- Be one clear sentence combining elements from 2+ successful algorithms
|
|
771
|
-
- Reference the base parent algorithm ID at the beginning like \"From gen02-003:\"
|
|
772
|
-
- Explicitly mention which elements to combine from which algorithms
|
|
773
|
-
|
|
774
|
-
Example output format:
|
|
775
|
-
From gen02-003: Combine VIX regime filter from gen02-003 with LSTM predictions from gen01-005
|
|
776
|
-
From gen02-003: Merge volatility regime detection from gen02-003 with ML momentum from gen01-007
|
|
777
|
-
From gen02-003: Integrate multi-timeframe signals from gen02-003 with correlation sizing from gen01-009
|
|
778
|
-
|
|
779
|
-
Output exactly $count lines now:"
|
|
780
|
-
|
|
781
|
-
echo "[INFO] Generating $count crossover hybrid ideas..."
|
|
782
|
-
|
|
783
|
-
# Get AI response
|
|
784
|
-
local ai_output
|
|
785
|
-
local ai_error
|
|
786
|
-
if ! ai_output=$(call_ai_with_limit_check "$prompt" "$CURRENT_GENERATION" 2>&1); then
|
|
787
|
-
ai_error="$ai_output"
|
|
788
|
-
|
|
789
|
-
# Check for specific error types
|
|
790
|
-
if echo "$ai_error" | grep -qi "rate.*limit\|too.*many.*requests"; then
|
|
791
|
-
echo "[ERROR] Hit API rate limit. Please wait a moment and try again." >&2
|
|
792
|
-
elif echo "$ai_error" | grep -qi "unauthorized\|api.*key\|authentication"; then
|
|
793
|
-
# Try to identify which provider failed
|
|
794
|
-
if echo "$ai_error" | grep -qi "codex\|o3"; then
|
|
795
|
-
echo "[ERROR] Codex/O3 authentication issue. Please check your Codex API key." >&2
|
|
796
|
-
elif echo "$ai_error" | grep -qi "gemini"; then
|
|
797
|
-
echo "[ERROR] Gemini authentication issue. Please check your Gemini API key." >&2
|
|
798
|
-
elif echo "$ai_error" | grep -qi "claude\|anthropic"; then
|
|
799
|
-
echo "[ERROR] Claude authentication issue. Please check your Anthropic API key." >&2
|
|
800
|
-
else
|
|
801
|
-
echo "[ERROR] API authentication issue. Please check your API key configuration." >&2
|
|
802
|
-
echo "[ERROR] Last attempted model was from generation $CURRENT_GENERATION strategy" >&2
|
|
803
|
-
fi
|
|
804
|
-
elif echo "$ai_error" | grep -qi "timeout\|timed.*out"; then
|
|
805
|
-
echo "[ERROR] Request timed out. The prompt may be too complex." >&2
|
|
806
|
-
else
|
|
807
|
-
echo "[ERROR] AI request failed: $ai_error" >&2
|
|
808
|
-
fi
|
|
809
|
-
return 1
|
|
810
|
-
fi
|
|
811
|
-
|
|
812
|
-
# Process the output using helper function
|
|
813
|
-
process_ai_ideas "$ai_output" "$count" "crossover" "$top_performers"
|
|
814
|
-
|
|
815
|
-
echo "[INFO] Crossover hybrid ideas generated successfully"
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
# Legacy AI generation mode (for backward compatibility)
|
|
819
|
-
ideate_ai_legacy() {
|
|
820
|
-
if [[ ! -f "$FULL_BRIEF_PATH" ]]; then
|
|
821
|
-
echo "[ERROR] $BRIEF_FILE not found. Run 'claude-evolve setup' first." >&2
|
|
822
|
-
exit 1
|
|
823
|
-
fi
|
|
824
|
-
|
|
825
|
-
# Get top performers for context
|
|
826
|
-
local top_performers=""
|
|
827
|
-
if [[ -f "$FULL_CSV_PATH" ]]; then
|
|
828
|
-
# Simple top performers extraction (lines with non-empty performance)
|
|
829
|
-
top_performers=$(awk -F, 'NR > 1 && $4 != "" { print $1 ": " $3 " (score: " $4 ")" }' "$FULL_CSV_PATH" | head -5)
|
|
830
|
-
fi
|
|
831
|
-
|
|
832
|
-
# Build prompt for description-only output
|
|
833
|
-
local prompt="Generate exactly $TOTAL_IDEAS novel algorithmic ideas for trading algorithm evolution.
|
|
834
|
-
|
|
835
|
-
Algorithm files for context:
|
|
836
|
-
- Base algorithm: $FULL_ALGORITHM_PATH
|
|
837
|
-
- Evolved algorithms: $FULL_OUTPUT_DIR/evolution_*.py
|
|
838
|
-
|
|
839
|
-
IMPORTANT: Before generating ideas, you should:
|
|
840
|
-
1. Read the base algorithm to understand the codebase structure and possibilities
|
|
841
|
-
2. Read ALL existing evolution_*.py files to see what modifications have been attempted
|
|
842
|
-
3. Consider which approaches might work well
|
|
843
|
-
|
|
844
|
-
Project Brief:
|
|
845
|
-
$(cat "$FULL_BRIEF_PATH")"
|
|
846
|
-
|
|
847
|
-
if [[ -n $top_performers ]]; then
|
|
848
|
-
prompt+="
|
|
849
|
-
|
|
850
|
-
Top Performing Algorithms So Far:
|
|
851
|
-
$top_performers"
|
|
852
|
-
fi
|
|
853
|
-
|
|
854
|
-
prompt+="
|
|
855
|
-
|
|
856
|
-
You MUST output EXACTLY $TOTAL_IDEAS lines, where each line is a single sentence describing a specific algorithmic change.
|
|
857
|
-
NO PREAMBLE, NO EXPLANATION, NO NUMBERING - just $TOTAL_IDEAS lines of algorithm descriptions.
|
|
858
|
-
|
|
859
|
-
Requirements:
|
|
860
|
-
- Each line should be one clear sentence describing an algorithmic approach
|
|
861
|
-
- Mix both parameter tuning and structural changes
|
|
862
|
-
- If building on existing algorithms, start with 'From ALGORITHM_ID:'
|
|
863
|
-
|
|
864
|
-
⚠️ AVOID ONLY: Kelly floor/cap adjustments that assume leverage > 1.0 (these get clamped and have no effect)
|
|
865
|
-
|
|
866
|
-
✅ EXPLORE ALL CREATIVE POSSIBILITIES INCLUDING:
|
|
867
|
-
- Machine Learning: Neural networks, ensemble methods, reinforcement learning (use train() method)
|
|
868
|
-
- Advanced Indicators: Custom combinations, multi-timeframe signals, cross-asset indicators
|
|
869
|
-
- Market Regime Detection: VIX patterns, correlation analysis, volatility clustering
|
|
870
|
-
- Risk Management: Dynamic stops, portfolio heat, correlation-based position sizing
|
|
871
|
-
- Alternative Strategies: New sub-strategies, momentum variants, mean reversion innovations
|
|
872
|
-
- Multi-Asset Signals: Sector rotation, bond yields, commodity signals
|
|
873
|
-
- Time-Based Patterns: Intraday effects, calendar anomalies, volatility timing
|
|
874
|
-
- Parameter Optimization: Entry thresholds, indicator periods, strategy weights
|
|
875
|
-
|
|
876
|
-
Output exactly $TOTAL_IDEAS lines now:"
|
|
877
|
-
|
|
878
|
-
echo "[INFO] Generating $TOTAL_IDEAS ideas (legacy mode)..."
|
|
879
|
-
|
|
880
|
-
# Get AI response
|
|
881
|
-
local ai_output
|
|
882
|
-
if ! ai_output=$(call_ai_with_limit_check "$prompt" "$CURRENT_GENERATION" 2>&1); then
|
|
883
|
-
echo "[WARN] AI failed to generate ideas" >&2
|
|
884
|
-
return 1
|
|
885
|
-
fi
|
|
886
|
-
|
|
887
|
-
# Process the output using helper function
|
|
888
|
-
# For legacy mode, we treat all as "novel" since we're not specifying a strategy
|
|
889
|
-
process_ai_ideas "$ai_output" "$TOTAL_IDEAS" "novel"
|
|
890
|
-
|
|
891
|
-
echo "[INFO] Legacy ideas generated"
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
# Determine generation number for this ideation run
|
|
895
|
-
CURRENT_GENERATION=$(get_next_generation)
|
|
896
|
-
echo "[INFO] Starting ideation for generation $CURRENT_GENERATION"
|
|
897
|
-
|
|
898
|
-
# Main execution
|
|
899
|
-
if [[ $use_strategies == true ]]; then
|
|
900
|
-
echo "[INFO] Multi-strategy AI generation mode"
|
|
901
|
-
ideate_ai_strategies
|
|
902
|
-
echo "[INFO] Ideation complete! Check $EVOLUTION_CSV for new ideas."
|
|
903
|
-
else
|
|
904
|
-
echo "[INFO] Legacy AI generation mode"
|
|
905
|
-
ideate_ai_legacy
|
|
906
|
-
echo "[INFO] Ideation complete! Check $EVOLUTION_CSV for new ideas."
|
|
907
|
-
fi
|