run-simulations
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseRun Simulations Skill
交易模拟运行Skill
You are helping set up and run trading engine simulations, then performing comprehensive diagnostic analysis.
你将协助完成交易引擎模拟的配置与运行,并执行全面的诊断分析。
Current Phase: DUAL-FOCUS (Validation + Optimization)
当前阶段:双重聚焦(验证+优化)
System confidence: ~85% accurate. The simulation system is largely trustworthy, but discrepancies still exist and are critical to find.
系统置信度:约85%准确。模拟系统整体可靠,但仍存在差异,且这些差异的排查至关重要。
Priority #1: ACCURACY DISCREPANCIES (Most Important)
优先级1:准确性差异(最关键)
Any gap between expected vs actual behavior is a potential bug or misunderstanding. These must be surfaced prominently:
- Does behavior match config parameters?
- Are there logical inconsistencies in the data?
- Do results align with what the strategy SHOULD produce?
When you spot a discrepancy, flag it prominently. Even small accuracy issues compound over thousands of trades.
预期行为与实际行为之间的任何差距都可能是潜在bug或理解偏差。必须重点突出这些问题:
- 行为是否与配置参数匹配?
- 数据中是否存在逻辑不一致?
- 结果是否符合策略应产生的预期?
发现差异时,请显著标记。即使是微小的准确性问题,在数千次交易中也会被放大。
Priority #2: PROFIT OPTIMIZATION (Active Research)
优先级2:利润优化(主动研究)
With a trustworthy system, we're now actively researching:
- Which configs perform best?
- What market conditions favor which strategies?
- How do parameters affect PnL?
Surface interesting profit patterns AND accuracy concerns. Both matter now.
IMPORTANT: This skill should be invoked BEFORE running simulations to help with setup decisions (config selection, segment selection via collections, batch sizing).
在系统可信的基础上,我们正在积极研究:
- 哪些配置表现最佳?
- 哪些市场条件更适合特定策略?
- 参数如何影响盈亏(PnL)?
既要呈现有趣的利润模式,也要关注准确性问题。两者当前都很重要。
重要提示:此Skill应在模拟运行前调用,以协助完成配置决策(配置选择、通过集合选择片段、批量规模设置)。
Recommended Batch Size
推荐批量运行规模
Current recommendation: 2,000-3,000 simulations per batch.
- Runs quickly (~30-60 seconds with tick caching)
- Provides statistically meaningful results
- More than 3,000 doesn't add much value at current stage
- Formula: configs × segments = total runs (e.g., 20 configs × 100 segments = 2,000 runs)
当前推荐:每批2000-3000次模拟
- 运行速度快(启用tick缓存后约30-60秒)
- 提供具有统计意义的结果
- 当前阶段超过3000次运行不会带来太多额外价值
- 计算公式:配置数量 × 片段数量 = 总运行次数(例如:20个配置 × 100个片段 = 2000次运行)
Phase 1: Setup & Run
阶段1:配置与运行
⚠️ USER INPUT TAKES PRIORITY
⚠️ 用户输入优先
If the user provides ANY arguments, instructions, or context when invoking this skill, those take absolute priority over all defaults below.
- User says "run config X" → run config X, ignore default config selection
- User says "test these 5 segments" → test those 5 segments, ignore default segment query
- User asks a specific question → answer that question, don't run the full default workflow
- User provides partial instructions → fill in gaps with defaults, but honor what they specified
The defaults below are ONLY for when the skill is invoked with no arguments at all.
如果用户在调用此Skill时提供了任何参数、指令或上下文,这些内容将绝对优先于以下所有默认设置。
- 用户说"run config X" → 运行配置X,忽略默认配置选择
- 用户说"test these 5 segments" → 测试这5个片段,忽略默认片段查询
- 用户提出具体问题 → 回答该问题,不执行完整的默认工作流
- 用户提供部分指令 → 使用默认值填补空白,但优先遵循用户指定的内容
以下默认设置仅适用于调用Skill时未提供任何参数的情况。
Default Behavior (no args only)
默认行为(仅无参数时)
Pick a diverse spread of configs and segments using segment collections (legacy filters are deprecated):
- Query available configs:
SELECT name, config FROM strategy_configs ORDER BY name - Select 10-20 configs covering different indicator types (EMA, RSI, Bollinger, combined)
- Choose or create a segment collection (AND-only annotations in v1):
bash
bun src/systems/trading-engine/bd-segments.ts list bun src/systems/trading-engine/bd-segments.ts create --name=high-activity --annotations=high_activity --limit=100 bun src/systems/trading-engine/bd-segments.ts preview --name=high-activity - Run batch simulation:
bash
bun src/systems/trading-engine/batch-runner.ts --config-pattern="<pattern>" --collection=high-activity --save
使用片段集合(旧版过滤器已弃用)选择多样化的配置和片段:
- 查询可用配置:
SELECT name, config FROM strategy_configs ORDER BY name - 选择10-20个覆盖不同指标类型的配置(EMA、RSI、布林带、组合指标)
- 选择或创建片段集合(v1版本仅支持AND类型的注解):
bash
bun src/systems/trading-engine/bd-segments.ts list bun src/systems/trading-engine/bd-segments.ts create --name=high-activity --annotations=high_activity --limit=100 bun src/systems/trading-engine/bd-segments.ts preview --name=high-activity - 运行批量模拟:
bash
bun src/systems/trading-engine/batch-runner.ts --config-pattern="<pattern>" --collection=high-activity --save
Batch Runner CLI Reference
Batch Runner CLI参考
Location:
src/systems/trading-engine/batch-runner.tsUsage:
bash
bun src/systems/trading-engine/batch-runner.ts [options]Options:
| Option | Short | Description |
|---|---|---|
| | Strategy config ID (can specify multiple) |
| | Run all available strategy configs |
| | Run configs matching name pattern (SQL LIKE) |
| Filter configs by strategy type (volatility, arb, grid) | |
| `--collection=NAME | ID` | |
| Preview collection selection and exit | |
| Initial capital in cents (default: 10000 = $100) | |
| | Number of parallel workers (default: 8) |
| | Save results to database |
| Show what would run without executing | |
| Pre-load N candles before segment for indicator warmup (default: 50) | |
| DB pool size for main batch process (default: 10) | |
| DB pool size for worker processes (default: 3) |
Examples:
bash
undefined位置:
src/systems/trading-engine/batch-runner.ts用法:
bash
bun src/systems/trading-engine/batch-runner.ts [options]选项:
| 选项 | 简写 | 描述 |
|---|---|---|
| | 策略配置ID(可指定多个) |
| | 运行所有可用策略配置 |
| | 运行名称匹配指定模式的配置(SQL LIKE语法) |
| 按策略类型过滤配置(波动率、套利、网格) | |
| `--collection=NAME | ID` | |
| 预览集合选择结果后退出 | |
| 初始资金(单位:分,默认值:10000 = 100美元) | |
| | 并行工作进程数量(默认值:8) |
| | 将结果保存到数据库 |
| 显示将要执行的操作但不实际运行 | |
| 为指标预热,在片段前预加载N根K线(默认值:50) | |
| 主批量进程的数据库连接池大小(默认值:10) | |
| 工作进程的数据库连接池大小(默认值:3) |
示例:
bash
undefinedRun one config on a segment collection
在片段集合上运行单个配置
bun src/systems/trading-engine/bd-segments.ts create --name=swings100 --annotations=high_activity
bun src/systems/trading-engine/batch-runner.ts --config=abc123 --collection=swings100 --save
bun src/systems/trading-engine/bd-segments.ts create --name=swings100 --annotations=high_activity
bun src/systems/trading-engine/batch-runner.ts --config=abc123 --collection=swings100 --save
Run all configs on a collection
在集合上运行所有配置
bun src/systems/trading-engine/batch-runner.ts --all-configs --collection=swings50 --save
bun src/systems/trading-engine/batch-runner.ts --all-configs --collection=swings50 --save
Run all configs on specific segment IDs (snapshot collection)
在特定片段ID上运行所有配置(快照集合)
bun src/systems/trading-engine/bd-segments.ts create --name=segment-set --segment-ids=949,950,951,952 --mode=snapshot
bun src/systems/trading-engine/batch-runner.ts --all-configs --collection=segment-set --save
bun src/systems/trading-engine/bd-segments.ts create --name=segment-set --segment-ids=949,950,951,952 --mode=snapshot
bun src/systems/trading-engine/batch-runner.ts --all-configs --collection=segment-set --save
Run configs matching "RSI-*" on high_activity segments
在高活跃度片段上运行名称匹配"RSI-*"的配置
bun src/systems/trading-engine/bd-segments.ts create --name=rsi-activity --annotations=high_activity
bun src/systems/trading-engine/batch-runner.ts --config-pattern="RSI-%" --collection=rsi-activity --save
bun src/systems/trading-engine/bd-segments.ts create --name=rsi-activity --annotations=high_activity
bun src/systems/trading-engine/batch-runner.ts --config-pattern="RSI-%" --collection=rsi-activity --save
Dry run to see what would execute
空运行以查看将要执行的操作
bun src/systems/trading-engine/batch-runner.ts --all-configs --collection=swings100 --dry-run
undefinedbun src/systems/trading-engine/batch-runner.ts --all-configs --collection=swings100 --dry-run
undefinedKey CLI Flags (Quick Reference)
关键CLI标记(快速参考)
- or
--collection=NAME|ID: REQUIRED segment collection selector-C - : Preview resolved segment list and exit
--show-selection - or
--config-pattern="TEST-%": Filter configs by name pattern-p - : Filter configs by strategy type
--strategy-type=grid
- 或
--collection=NAME|ID:必填的片段集合选择器-C - :预览解析后的片段列表后退出
--show-selection - 或
--config-pattern="TEST-%":按名称模式过滤配置-p - :按策略类型过滤配置
--strategy-type=grid
Phase 2: Comprehensive Analysis (ALWAYS RUN)
阶段2:全面分析(必须执行)
After simulations complete, run ALL of the following diagnostic queries. Present results in tables.
模拟完成后,运行以下所有诊断查询。以表格形式呈现结果。
2.1 Core Stats
2.1 核心统计数据
sql
SELECT
sc.name,
COUNT(*) as runs,
ROUND(AVG(trade_count)::numeric, 1) as avg_trades,
ROUND(STDDEV(trade_count)::numeric, 1) as stddev_trades,
MIN(trade_count) as min_trades,
MAX(trade_count) as max_trades
FROM (
SELECT r.id, sc.name, COUNT(t.id) as trade_count
FROM sim_runs r
JOIN strategy_configs sc ON r.config_id = sc.id
LEFT JOIN sim_trades t ON t.run_id = r.id
WHERE r.created_at > NOW() - INTERVAL '1 hour'
GROUP BY r.id, sc.name
) sub
JOIN strategy_configs sc ON sc.name = sub.name
GROUP BY sc.name
ORDER BY avg_trades;sql
SELECT
sc.name,
COUNT(*) as runs,
ROUND(AVG(trade_count)::numeric, 1) as avg_trades,
ROUND(STDDEV(trade_count)::numeric, 1) as stddev_trades,
MIN(trade_count) as min_trades,
MAX(trade_count) as max_trades
FROM (
SELECT r.id, sc.name, COUNT(t.id) as trade_count
FROM sim_runs r
JOIN strategy_configs sc ON r.config_id = sc.id
LEFT JOIN sim_trades t ON t.run_id = r.id
WHERE r.created_at > NOW() - INTERVAL '1 hour'
GROUP BY r.id, sc.name
) sub
JOIN strategy_configs sc ON sc.name = sub.name
GROUP BY sc.name
ORDER BY avg_trades;2.2 Entry Signal Frequency (RED FLAG: median < 60s is suspicious)
2.2 入场信号频率(红色预警:中位数<60秒则可疑)
sql
WITH entries AS (
SELECT
t.run_id, sc.name as config, t.entry_at,
LAG(t.entry_at) OVER (PARTITION BY t.run_id ORDER BY t.entry_at) as prev_entry
FROM sim_trades t
JOIN sim_runs r ON t.run_id = r.id
JOIN strategy_configs sc ON r.config_id = sc.id
WHERE r.created_at > NOW() - INTERVAL '1 hour'
)
SELECT
config,
COUNT(*) as entry_gaps,
ROUND(AVG((entry_at - prev_entry)/1000.0)::numeric, 1) as avg_gap_sec,
ROUND(PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY (entry_at - prev_entry)/1000.0)::numeric, 1) as median_gap_sec,
COUNT(*) FILTER (WHERE entry_at - prev_entry < 1000) as gaps_under_1s,
COUNT(*) FILTER (WHERE entry_at - prev_entry < 5000) as gaps_under_5s,
COUNT(*) FILTER (WHERE entry_at - prev_entry < 60000) as gaps_under_1min
FROM entries
WHERE prev_entry IS NOT NULL
GROUP BY config
ORDER BY median_gap_sec;Interpretation: Median gaps < 60s suggest overtrading. Healthy configs should have gaps in minutes (20-30min typical). Gaps < 1s are a MAJOR RED FLAG - indicates indicator firing constantly.
sql
WITH entries AS (
SELECT
t.run_id, sc.name as config, t.entry_at,
LAG(t.entry_at) OVER (PARTITION BY t.run_id ORDER BY t.entry_at) as prev_entry
FROM sim_trades t
JOIN sim_runs r ON t.run_id = r.id
JOIN strategy_configs sc ON r.config_id = sc.id
WHERE r.created_at > NOW() - INTERVAL '1 hour'
)
SELECT
config,
COUNT(*) as entry_gaps,
ROUND(AVG((entry_at - prev_entry)/1000.0)::numeric, 1) as avg_gap_sec,
ROUND(PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY (entry_at - prev_entry)/1000.0)::numeric, 1) as median_gap_sec,
COUNT(*) FILTER (WHERE entry_at - prev_entry < 1000) as gaps_under_1s,
COUNT(*) FILTER (WHERE entry_at - prev_entry < 5000) as gaps_under_5s,
COUNT(*) FILTER (WHERE entry_at - prev_entry < 60000) as gaps_under_1min
FROM entries
WHERE prev_entry IS NOT NULL
GROUP BY config
ORDER BY median_gap_sec;解读:中位数间隔<60秒意味着过度交易。健康的配置间隔应在分钟级别(通常20-30分钟)。间隔<1秒是重大红色预警,表明指标持续触发。
2.3 Position Overlap
2.3 仓位重叠
sql
-- How many concurrent positions on average?
WITH trade_events AS (
SELECT t.run_id, sc.name as config, t.entry_at as ts, 1 as delta
FROM sim_trades t
JOIN sim_runs r ON t.run_id = r.id
JOIN strategy_configs sc ON r.config_id = sc.id
WHERE r.created_at > NOW() - INTERVAL '1 hour'
UNION ALL
SELECT t.run_id, sc.name as config, t.exit_at as ts, -1 as delta
FROM sim_trades t
JOIN sim_runs r ON t.run_id = r.id
JOIN strategy_configs sc ON r.config_id = sc.id
WHERE r.created_at > NOW() - INTERVAL '1 hour' AND t.exit_at IS NOT NULL
),
running_pos AS (
SELECT run_id, config, ts,
SUM(delta) OVER (PARTITION BY run_id ORDER BY ts, delta DESC) as open_positions
FROM trade_events
)
SELECT
config,
MAX(open_positions) as max_concurrent,
ROUND(AVG(open_positions)::numeric, 2) as avg_concurrent,
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY open_positions) as median_concurrent
FROM running_pos
GROUP BY config
ORDER BY avg_concurrent DESC;sql
-- 平均并发仓位数量?
WITH trade_events AS (
SELECT t.run_id, sc.name as config, t.entry_at as ts, 1 as delta
FROM sim_trades t
JOIN sim_runs r ON t.run_id = r.id
JOIN strategy_configs sc ON r.config_id = sc.id
WHERE r.created_at > NOW() - INTERVAL '1 hour'
UNION ALL
SELECT t.run_id, sc.name as config, t.exit_at as ts, -1 as delta
FROM sim_trades t
JOIN sim_runs r ON t.run_id = r.id
JOIN strategy_configs sc ON r.config_id = sc.id
WHERE r.created_at > NOW() - INTERVAL '1 hour' AND t.exit_at IS NOT NULL
),
running_pos AS (
SELECT run_id, config, ts,
SUM(delta) OVER (PARTITION BY run_id ORDER BY ts, delta DESC) as open_positions
FROM trade_events
)
SELECT
config,
MAX(open_positions) as max_concurrent,
ROUND(AVG(open_positions)::numeric, 2) as avg_concurrent,
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY open_positions) as median_concurrent
FROM running_pos
GROUP BY config
ORDER BY avg_concurrent DESC;2.4 Holding Duration Distribution
2.4 持仓时长分布
sql
SELECT
sc.name as config,
CASE
WHEN t.holding_duration_ms < 30000 THEN '<30s'
WHEN t.holding_duration_ms < 60000 THEN '30-60s'
WHEN t.holding_duration_ms < 120000 THEN '1-2min'
WHEN t.holding_duration_ms < 180000 THEN '2-3min'
WHEN t.holding_duration_ms < 240000 THEN '3-4min'
WHEN t.holding_duration_ms < 300000 THEN '4-5min'
ELSE '5min+'
END as hold_bucket,
COUNT(*) as trades,
ROUND(AVG(t.net_pnl_cents)::numeric, 1) as avg_pnl,
ROUND(COUNT(*)::numeric / SUM(COUNT(*)) OVER (PARTITION BY sc.name) * 100, 1) as pct
FROM sim_trades t
JOIN sim_runs r ON t.run_id = r.id
JOIN strategy_configs sc ON r.config_id = sc.id
WHERE r.created_at > NOW() - INTERVAL '1 hour' AND t.holding_duration_ms IS NOT NULL
GROUP BY sc.name, hold_bucket
ORDER BY sc.name, MIN(t.holding_duration_ms);sql
SELECT
sc.name as config,
CASE
WHEN t.holding_duration_ms < 30000 THEN '<30s'
WHEN t.holding_duration_ms < 60000 THEN '30-60s'
WHEN t.holding_duration_ms < 120000 THEN '1-2min'
WHEN t.holding_duration_ms < 180000 THEN '2-3min'
WHEN t.holding_duration_ms < 240000 THEN '3-4min'
WHEN t.holding_duration_ms < 300000 THEN '4-5min'
ELSE '5min+'
END as hold_bucket,
COUNT(*) as trades,
ROUND(AVG(t.net_pnl_cents)::numeric, 1) as avg_pnl,
ROUND(COUNT(*)::numeric / SUM(COUNT(*)) OVER (PARTITION BY sc.name) * 100, 1) as pct
FROM sim_trades t
JOIN sim_runs r ON t.run_id = r.id
JOIN strategy_configs sc ON r.config_id = sc.id
WHERE r.created_at > NOW() - INTERVAL '1 hour' AND t.holding_duration_ms IS NOT NULL
GROUP BY sc.name, hold_bucket
ORDER BY sc.name, MIN(t.holding_duration_ms);2.5 Exit Reason Analysis
2.5 离场原因分析
sql
SELECT
sc.name as config,
t.exit_reason,
COUNT(*) as trades,
ROUND(AVG(t.net_pnl_cents)::numeric, 1) as avg_pnl,
ROUND(COUNT(*)::numeric / SUM(COUNT(*)) OVER (PARTITION BY sc.name) * 100, 1) as pct
FROM sim_trades t
JOIN sim_runs r ON t.run_id = r.id
JOIN strategy_configs sc ON r.config_id = sc.id
WHERE r.created_at > NOW() - INTERVAL '1 hour'
GROUP BY sc.name, t.exit_reason
ORDER BY sc.name, trades DESC;sql
SELECT
sc.name as config,
t.exit_reason,
COUNT(*) as trades,
ROUND(AVG(t.net_pnl_cents)::numeric, 1) as avg_pnl,
ROUND(COUNT(*)::numeric / SUM(COUNT(*)) OVER (PARTITION BY sc.name) * 100, 1) as pct
FROM sim_trades t
JOIN sim_runs r ON t.run_id = r.id
JOIN strategy_configs sc ON r.config_id = sc.id
WHERE r.created_at > NOW() - INTERVAL '1 hour'
GROUP BY sc.name, t.exit_reason
ORDER BY sc.name, trades DESC;2.6 YES vs NO Side Analysis (IMPORTANT - check for asymmetries)
2.6 YES vs NO方向分析(重要 - 检查不对称性)
sql
SELECT
sc.name as config,
t.side,
COUNT(*) as trades,
ROUND(AVG(t.net_pnl_cents)::numeric, 1) as avg_pnl,
ROUND(AVG(CASE WHEN t.net_pnl_cents > 0 THEN 1 ELSE 0 END)::numeric * 100, 1) as win_pct,
ROUND(AVG(t.entry_price)::numeric, 1) as avg_entry_price,
ROUND(AVG(t.exit_price)::numeric, 1) as avg_exit_price,
ROUND(AVG(t.quantity)::numeric, 1) as avg_qty
FROM sim_trades t
JOIN sim_runs r ON t.run_id = r.id
JOIN strategy_configs sc ON r.config_id = sc.id
WHERE r.created_at > NOW() - INTERVAL '1 hour'
GROUP BY sc.name, t.side
ORDER BY sc.name, t.side;Interpretation: Significant asymmetry between YES/NO performance suggests bugs in price conversion or side selection logic. Both sides should have similar characteristics unless the strategy explicitly favors one.
sql
SELECT
sc.name as config,
t.side,
COUNT(*) as trades,
ROUND(AVG(t.net_pnl_cents)::numeric, 1) as avg_pnl,
ROUND(AVG(CASE WHEN t.net_pnl_cents > 0 THEN 1 ELSE 0 END)::numeric * 100, 1) as win_pct,
ROUND(AVG(t.entry_price)::numeric, 1) as avg_entry_price,
ROUND(AVG(t.exit_price)::numeric, 1) as avg_exit_price,
ROUND(AVG(t.quantity)::numeric, 1) as avg_qty
FROM sim_trades t
JOIN sim_runs r ON t.run_id = r.id
JOIN strategy_configs sc ON r.config_id = sc.id
WHERE r.created_at > NOW() - INTERVAL '1 hour'
GROUP BY sc.name, t.side
ORDER BY sc.name, t.side;解读:YES与NO方向的表现存在显著不对称性,表明价格转换或方向选择逻辑存在bug。除非策略明确偏向某一方向,否则两者应具有相似特征。
2.7 Position Sizing Verification
2.7 仓位规模验证
sql
-- Check if fills match expected sizes and align with order book
SELECT
sc.name as config,
t.quantity as fill_qty,
COUNT(*) as occurrences,
ROUND(AVG(t.entry_price)::numeric, 1) as avg_entry_price,
ROUND(AVG(t.net_pnl_cents)::numeric, 1) as avg_pnl
FROM sim_trades t
JOIN sim_runs r ON t.run_id = r.id
JOIN strategy_configs sc ON r.config_id = sc.id
WHERE r.created_at > NOW() - INTERVAL '1 hour'
GROUP BY sc.name, t.quantity
ORDER BY sc.name, t.quantity;Check: Does quantity match config's maxTradeSize? Are partial fills happening? Compare with maxPositionPerMarket.
sql
-- 检查成交规模是否符合预期,且与订单簿一致
SELECT
sc.name as config,
t.quantity as fill_qty,
COUNT(*) as occurrences,
ROUND(AVG(t.entry_price)::numeric, 1) as avg_entry_price,
ROUND(AVG(t.net_pnl_cents)::numeric, 1) as avg_pnl
FROM sim_trades t
JOIN sim_runs r ON t.run_id = r.id
JOIN strategy_configs sc ON r.config_id = sc.id
WHERE r.created_at > NOW() - INTERVAL '1 hour'
GROUP BY sc.name, t.quantity
ORDER BY sc.name, t.quantity;检查点:成交数量是否与配置中的maxTradeSize匹配?是否存在部分成交?与maxPositionPerMarket进行比较。
2.8 Trade Sequence Performance
2.8 交易序列表现
sql
WITH numbered_trades AS (
SELECT t.*, sc.name as config,
ROW_NUMBER() OVER (PARTITION BY t.run_id ORDER BY t.entry_at) as trade_num
FROM sim_trades t
JOIN sim_runs r ON t.run_id = r.id
JOIN strategy_configs sc ON r.config_id = sc.id
WHERE r.created_at > NOW() - INTERVAL '1 hour'
)
SELECT
config,
CASE
WHEN trade_num = 1 THEN '1st'
WHEN trade_num BETWEEN 2 AND 5 THEN '2-5th'
WHEN trade_num BETWEEN 6 AND 10 THEN '6-10th'
WHEN trade_num BETWEEN 11 AND 20 THEN '11-20th'
ELSE '21st+'
END as position,
COUNT(*) as trades,
ROUND(AVG(net_pnl_cents)::numeric, 1) as avg_pnl,
ROUND(AVG(CASE WHEN net_pnl_cents > 0 THEN 1 ELSE 0 END)::numeric * 100, 1) as win_pct
FROM numbered_trades
GROUP BY config, position
ORDER BY config, MIN(trade_num);sql
WITH numbered_trades AS (
SELECT t.*, sc.name as config,
ROW_NUMBER() OVER (PARTITION BY t.run_id ORDER BY t.entry_at) as trade_num
FROM sim_trades t
JOIN sim_runs r ON t.run_id = r.id
JOIN strategy_configs sc ON r.config_id = sc.id
WHERE r.created_at > NOW() - INTERVAL '1 hour'
)
SELECT
config,
CASE
WHEN trade_num = 1 THEN '1st'
WHEN trade_num BETWEEN 2 AND 5 THEN '2-5th'
WHEN trade_num BETWEEN 6 AND 10 THEN '6-10th'
WHEN trade_num BETWEEN 11 AND 20 THEN '11-20th'
ELSE '21st+'
END as position,
COUNT(*) as trades,
ROUND(AVG(net_pnl_cents)::numeric, 1) as avg_pnl,
ROUND(AVG(CASE WHEN net_pnl_cents > 0 THEN 1 ELSE 0 END)::numeric * 100, 1) as win_pct
FROM numbered_trades
GROUP BY config, position
ORDER BY config, MIN(trade_num);2.9 Market Segment Analysis
2.9 市场片段分析
sql
SELECT
ms.definition_name,
COUNT(DISTINCT r.id) as runs,
COUNT(t.id) as trades,
ROUND(AVG(r.total_pnl_cents)::numeric, 1) as avg_run_pnl,
ROUND(AVG((ms.metrics->>'swing_count')::int)::numeric, 1) as avg_swings,
ROUND(AVG((ms.metrics->>'reversion_rate')::float)::numeric, 2) as avg_reversion_rate
FROM sim_runs r
JOIN market_segments ms ON ms.source_meta->>'legacy_test_case_id' = r.test_case_id::text
LEFT JOIN sim_trades t ON t.run_id = r.id
JOIN strategy_configs sc ON r.config_id = sc.id
WHERE r.created_at > NOW() - INTERVAL '1 hour'
GROUP BY ms.definition_name
ORDER BY runs DESC;sql
SELECT
ms.definition_name,
COUNT(DISTINCT r.id) as runs,
COUNT(t.id) as trades,
ROUND(AVG(r.total_pnl_cents)::numeric, 1) as avg_run_pnl,
ROUND(AVG((ms.metrics->>'swing_count')::int)::numeric, 1) as avg_swings,
ROUND(AVG((ms.metrics->>'reversion_rate')::float)::numeric, 2) as avg_reversion_rate
FROM sim_runs r
JOIN market_segments ms ON ms.source_meta->>'legacy_test_case_id' = r.test_case_id::text
LEFT JOIN sim_trades t ON t.run_id = r.id
JOIN strategy_configs sc ON r.config_id = sc.id
WHERE r.created_at > NOW() - INTERVAL '1 hour'
GROUP BY ms.definition_name
ORDER BY runs DESC;2.10 Run Health Check
2.10 运行健康检查
sql
SELECT status, COUNT(*) as count
FROM sim_runs
WHERE created_at > NOW() - INTERVAL '1 hour'
GROUP BY status;RED FLAG: Any "running" status after batch completes = crashed simulations.
sql
SELECT status, COUNT(*) as count
FROM sim_runs
WHERE created_at > NOW() - INTERVAL '1 hour'
GROUP BY status;红色预警:批量运行完成后仍存在"running"状态的记录,说明模拟崩溃。
Phase 3: Log Analysis (ALWAYS RUN)
阶段3:日志分析(必须执行)
Check recent simulation logs for anomalies:
bash
undefined检查近期模拟日志中的异常:
bash
undefinedFind most recent sim log
查找最新的模拟日志
ls -lt logs/sim/ | head -5
ls -lt logs/sim/ | head -5
Sample entries from most recent log with content
从最新日志中提取样本内容
LOG=$(ls -ltS logs/sim/*.log | head -1 | awk '{print $NF}')
echo "Analyzing: $LOG ($(du -h "$LOG" | cut -f1))"
LOG=$(ls -ltS logs/sim/*.log | head -1 | awk '{print $NF}')
echo "Analyzing: $LOG ($(du -h "$LOG" | cut -f1))"
Check log volume by category (PERFORMANCE RED FLAG: >1M indicator logs)
按类别检查日志量(性能红色预警:指标日志超过100万条)
echo "Log volume by category:"
rg '"category"' "$LOG" | jq -r '.category' 2>/dev/null | sort | uniq -c | sort -rn
echo "Log volume by category:"
rg '"category"' "$LOG" | jq -r '.category' 2>/dev/null | sort | uniq -c | sort -rn
Check run duration from timestamps
根据时间戳检查运行时长
echo "Run duration:"
FIRST_TS=$(head -1 "$LOG" | jq -r '.time' 2>/dev/null)
LAST_TS=$(tail -1 "$LOG" | jq -r '.time' 2>/dev/null)
if [ "$FIRST_TS" != "null" ] && [ "$LAST_TS" != "null" ]; then
echo "Duration: $(( (LAST_TS - FIRST_TS) / 1000 )) seconds"
fi
echo "Run duration:"
FIRST_TS=$(head -1 "$LOG" | jq -r '.time' 2>/dev/null)
LAST_TS=$(tail -1 "$LOG" | jq -r '.time' 2>/dev/null)
if [ "$FIRST_TS" != "null" ] && [ "$LAST_TS" != "null" ]; then
echo "Duration: $(( (LAST_TS - FIRST_TS) / 1000 )) seconds"
fi
Count exit reasons
统计离场原因分布
echo "Exit reason distribution:"
rg '"reason"' "$LOG" | jq -r '.reason' 2>/dev/null | sort | uniq -c | sort -rn | head -20
echo "Exit reason distribution:"
rg '"reason"' "$LOG" | jq -r '.reason' 2>/dev/null | sort | uniq -c | sort -rn | head -20
Check for errors
检查错误
echo "Errors in log:"
rg -i '"level":50' "$LOG" | head -10
echo "Errors in log:"
rg -i '"level":50' "$LOG" | head -10
Check for warnings
检查警告
echo "Warnings in log:"
rg -i '"level":40' "$LOG" | head -10
**Look for**:
- Unusual exit reasons (not profit_target, time_limit, collapse, end_of_data)
- Error level (50) entries
- Patterns suggesting bugs (repeated identical entries, missing fields)
- **PERFORMANCE**: Log file > 500MB = excessive logging
- **PERFORMANCE**: >1M indicator category logs = debug logging bottleneckecho "Warnings in log:"
rg -i '"level":40' "$LOG" | head -10
**需要关注的内容**:
- 异常离场原因(非profit_target、time_limit、collapse、end_of_data)
- 错误级别(50)的日志条目
- 表明bug的模式(重复的相同条目、缺失字段)
- **性能问题**:日志文件>500MB = 日志记录过多
- **性能问题**:指标类别日志>100万条 = 调试日志成为瓶颈Phase 3.5: Performance Analysis
阶段3.5:性能分析
Check simulation throughput:
sql
-- Runs per second over recent batch
SELECT
DATE_TRUNC('minute', created_at) as minute,
COUNT(*) as runs,
ROUND(COUNT(*)::numeric / 60, 1) as runs_per_sec
FROM sim_runs
WHERE created_at > NOW() - INTERVAL '1 hour'
GROUP BY minute
ORDER BY minute DESC
LIMIT 10;Expected throughput: 20-40 runs/sec with tick caching. If < 10 runs/sec, investigate:
- Is tick cache being used? (check for "Pre-loaded" in batch script output)
- Is indicator debug logging enabled? (check log size)
- Are workers I/O bound? (check worker count vs CPU cores)
检查模拟吞吐量:
sql
-- 近期批量运行的每秒运行次数
SELECT
DATE_TRUNC('minute', created_at) as minute,
COUNT(*) as runs,
ROUND(COUNT(*)::numeric / 60, 1) as runs_per_sec
FROM sim_runs
WHERE created_at > NOW() - INTERVAL '1 hour'
GROUP BY minute
ORDER BY minute DESC
LIMIT 10;预期吞吐量:启用tick缓存后为20-40次运行/秒。如果<10次运行/秒,需排查:
- 是否使用了tick缓存?(检查批量脚本输出中的"Pre-loaded")
- 是否启用了指标调试日志?(检查日志大小)
- 工作进程是否受I/O限制?(检查工作进程数量与CPU核心数的匹配情况)
Phase 4: Analysis Summary
阶段4:分析总结
DUAL FOCUS: Surface both accuracy concerns AND profit insights.
双重聚焦:既要突出准确性问题,也要呈现利润洞察。
First: Accuracy Check (Priority #1)
首先:准确性检查(优先级1)
Flag any discrepancies between expected vs actual behavior:
- Does config behavior match parameters?
- Are there unexplained patterns or anomalies?
- Do metrics make logical sense?
Accuracy issues take precedence. A 1% accuracy bug can invalidate profit analysis.
标记预期行为与实际行为之间的任何差异:
- 配置行为是否与参数匹配?
- 是否存在无法解释的模式或异常?
- 指标是否符合逻辑?
准确性问题优先。1%的准确性bug可能会使利润分析完全失效。
Then: Profit Insights (Priority #2)
其次:利润洞察(优先级2)
With accuracy validated, analyze:
- Which configs are most profitable?
- What patterns emerge across market conditions?
- Are there optimization opportunities?
在准确性验证通过后,分析:
- 哪些配置盈利能力最强?
- 不同市场条件下呈现出哪些模式?
- 是否存在优化机会?
Validation Questions to Answer
需要回答的验证问题
For each finding, ask: "Does this match what we'd expect? If not, why?"
| Observation | Expected Behavior | Actual | Match? | If No, Investigate |
|---|---|---|---|---|
| Entry gaps | Based on indicator params | ? | ? | Indicator calculation? Candle aggregation? |
| Exit reasons | Balanced mix | ? | ? | Exit logic? Threshold bugs? |
| YES vs NO performance | Similar (market is symmetric) | ? | ? | Price conversion? Side selection? |
| Position sizes | Match config maxTradeSize | ? | ? | Fill logic? Depth parsing? |
| Holding durations | Spread across buckets | ? | ? | Exit conditions firing? |
| Trade sequence | Later trades ≈ earlier | ? | ? | State accumulation bugs? |
| Bollinger/other indicators | Should trigger sometimes | ? | ? | Indicator implementation? |
对于每个发现,思考:"这符合我们的预期吗?如果不符合,原因是什么?"
| 观察结果 | 预期行为 | 实际情况 | 是否匹配? | 若不匹配,需排查 |
|---|---|---|---|---|
| 入场间隔 | 基于指标参数 | ? | ? | 指标计算?K线聚合? |
| 离场原因 | 均衡分布 | ? | ? | 离场逻辑?阈值bug? |
| YES vs NO表现 | 相似(市场对称) | ? | ? | 价格转换?方向选择? |
| 仓位规模 | 与配置的maxTradeSize匹配 | ? | ? | 成交逻辑?深度解析? |
| 持仓时长 | 分布在多个区间 | ? | ? | 离场条件触发? |
| 交易序列 | 后期交易与前期近似 | ? | ? | 状态累积bug? |
| 布林带/其他指标 | 应偶尔触发 | ? | ? | 指标实现? |
Key Validation Checks
关键验证检查
-
Indicator Firing Frequency
- Does the gap between entries match what the indicator period implies?
- EMA(20) with 60s candles = 20 min of data needed. Are we seeing entries faster than that makes sense?
-
Price/Side Consistency
- YES and NO should be mirror images. Major asymmetry = likely bug in price handling.
- Check: Are we converting bid/ask correctly for each side?
-
Config Parameters Actually Applied
- Is stopLossCents actually triggering at that price?
- Is profitTargetCents actually triggering?
- Is maxSpreadToEnter being checked?
-
Data Flow Integrity
- Are ticks reaching the strategy in order?
- Is depth data being parsed correctly?
- Are fills being recorded accurately?
-
指标触发频率
- 入场间隔是否与指标周期的预期一致?
- 20周期EMA(60秒K线)需要20分钟的数据。是否出现了比预期更快的入场信号?
-
价格/方向一致性
- YES和NO方向应互为镜像。显著不对称性表明价格处理存在bug。
- 检查:是否为每个方向正确转换了买卖价?
-
配置参数是否实际生效
- stopLossCents是否确实在指定价格触发?
- profitTargetCents是否确实触发?
- 是否检查了maxSpreadToEnter?
-
数据流完整性
- 行情tick是否按顺序传递给策略?
- 深度数据是否解析正确?
- 成交记录是否准确?
Phase 5: Findings & Next Steps
阶段5:发现与下一步计划
Based on analysis, organize findings into:
基于分析结果,将发现整理为以下类别:
Accuracy Concerns (Surface First)
准确性问题(优先呈现)
- Likely Bugs - Discrepancies that suggest code errors
- "X should be Y but we see Z" → investigate code path
- Unclear Behavior - Things we don't understand yet
- "We expected X, got Y, not sure why" → needs deeper investigation
- Confirmed Working - Things that match expectations
- "This behaves as expected" → increased confidence
- 疑似Bug - 表明代码错误的差异
- "X应该是Y,但实际是Z" → 排查代码路径
- 行为不明确 - 我们尚未理解的现象
- "我们预期是X,实际是Y,原因不明" → 需要深入排查
- 确认正常工作 - 符合预期的现象
- "此行为符合预期" → 提升置信度
Profit Insights (Surface Second)
利润洞察(其次呈现)
- Top Performers - Which configs show best results?
- Market Patterns - What conditions favor which strategies?
- Optimization Opportunities - Parameter tuning suggestions
- 表现最佳的配置 - 哪些配置结果最好?
- 市场模式 - 哪些条件更适合特定策略?
- 优化机会 - 参数调优建议
Next Steps
下一步计划
- Investigation priorities for accuracy concerns
- Experiments to validate profit hypotheses
- Config variations to test
Remember: Accuracy comes first. Surface discrepancies prominently, then provide profit optimization insights. Both matter, but a small accuracy bug can invalidate all profit analysis.
- 准确性问题的排查优先级
- 验证利润假设的实验
- 需测试的配置变体
记住:准确性优先。先突出差异,再提供利润优化洞察。两者都很重要,但微小的准确性bug可能会使所有利润分析失效。