Make analytics granular - individual tools + selective analyze_report

**Granular Analytics Tools (8 new tools):**
- analyze_monthly_pnl - Monthly profit/loss breakdown
- analyze_drawdown_events - Drawdown events from balance curve
- analyze_top_losses - Top N worst losses with grid depth
- analyze_loss_sequences - Consecutive loss streaks analysis
- analyze_position_pairs - Entry/exit position pairs
- analyze_direction_bias - Long vs Short performance stats
- analyze_streaks - Win/loss streaks with dates
- analyze_concurrent_peak - Peak concurrent open positions

**Updated analyze_report:**
- Now supports selective analytics via 'analytics' array parameter
- Runs all analytics by default (backward compatible)
- Optional top_losses_limit parameter
- Returns list of analytics that were run

**Changes:**
- analytics/analyze.rs: Made all analysis methods public
- tools/definitions.rs: Added 8 new tool definitions + updated analyze_report schema
- tools/handlers/mod.rs: Added dispatch for new tools
- tools/handlers/analysis.rs: Added helper load_report_data() + 8 granular handlers + selective analyze_report logic
This commit is contained in:
Devid HW
2026-04-19 02:13:33 +07:00
parent e94ec8153d
commit 1f63505cb9
4 changed files with 339 additions and 17 deletions
+8 -8
View File
@@ -34,7 +34,7 @@ impl DealAnalyzer {
}
}
fn monthly_pnl(&self, deals: &[Deal]) -> Vec<MonthlyPnl> {
pub fn monthly_pnl(&self, deals: &[Deal]) -> Vec<MonthlyPnl> {
let mut monthly: HashMap<String, (f64, i32)> = HashMap::new();
for deal in deals {
@@ -71,7 +71,7 @@ impl DealAnalyzer {
result
}
fn reconstruct_dd_events(&self, deals: &[Deal], _metrics: &Metrics) -> Vec<DrawdownEvent> {
pub fn reconstruct_dd_events(&self, deals: &[Deal], _metrics: &Metrics) -> Vec<DrawdownEvent> {
let mut balance_curve = Vec::new();
let mut peak_balance: f64 = 0.0;
let mut initial_balance: Option<f64> = None;
@@ -178,7 +178,7 @@ impl DealAnalyzer {
event
}
fn top_losses(&self, deals: &[Deal], n: usize) -> Vec<LossEntry> {
pub fn top_losses(&self, deals: &[Deal], n: usize) -> Vec<LossEntry> {
let mut losses: Vec<LossEntry> = deals
.iter()
.filter(|d| d.profit < 0.0)
@@ -196,7 +196,7 @@ impl DealAnalyzer {
losses
}
fn loss_sequences(&self, deals: &[Deal]) -> Vec<LossSequence> {
pub fn loss_sequences(&self, deals: &[Deal]) -> Vec<LossSequence> {
let closed: Vec<&Deal> = deals
.iter()
.filter(|d| d.entry.to_lowercase().contains("out") && d.profit != 0.0)
@@ -241,7 +241,7 @@ impl DealAnalyzer {
sequences
}
fn position_pairs(&self, deals: &[Deal]) -> Vec<PositionPair> {
pub fn position_pairs(&self, deals: &[Deal]) -> Vec<PositionPair> {
let mut open_pos: HashMap<String, &Deal> = HashMap::new();
let mut pairs = Vec::new();
@@ -278,7 +278,7 @@ impl DealAnalyzer {
pairs
}
fn direction_bias(&self, deals: &[Deal]) -> HashMap<String, DirectionStats> {
pub fn direction_bias(&self, deals: &[Deal]) -> HashMap<String, DirectionStats> {
let mut stats: HashMap<String, (i32, i32, f64)> = HashMap::new();
stats.insert("buy".to_string(), (0, 0, 0.0));
stats.insert("sell".to_string(), (0, 0, 0.0));
@@ -314,7 +314,7 @@ impl DealAnalyzer {
.collect()
}
fn streak_analysis(&self, deals: &[Deal]) -> StreakAnalysis {
pub fn streak_analysis(&self, deals: &[Deal]) -> StreakAnalysis {
let closed: Vec<&Deal> = deals
.iter()
.filter(|d| d.entry.to_lowercase().contains("out") && d.profit != 0.0)
@@ -372,7 +372,7 @@ impl DealAnalyzer {
}
}
fn concurrent_peak(&self, deals: &[Deal]) -> ConcurrentPeak {
pub fn concurrent_peak(&self, deals: &[Deal]) -> ConcurrentPeak {
let mut events: Vec<(DateTime<chrono::Utc>, i32, &Deal)> = Vec::new();
for deal in deals {