1717from vali_objects .utils .ledger_utils import LedgerUtils
1818from vali_objects .scoring .scoring import Scoring
1919from vali_objects .utils .metrics import Metrics
20+ from vali_objects .utils .asset_segmentation import AssetSegmentation
2021from vali_objects .vali_dataclasses .perf_ledger import PerfLedgerManager , TP_ID_PORTFOLIO
2122from vali_objects .utils .risk_profiling import RiskProfiling
2223from vali_objects .vali_dataclasses .perf_ledger import PerfLedger
@@ -328,6 +329,39 @@ def calculate_all_daily_returns(self, filtered_ledger: dict[str, dict[str, PerfL
328329 for hotkey , ledgers in filtered_ledger .items ()
329330 }
330331
332+ def calculate_subcategory_daily_returns (self , filtered_ledger : dict [str , dict [str , PerfLedger ]]) -> dict [str , dict [str , dict [str , float ]]]:
333+ """
334+ Calculate daily returns for each asset subcategory for all miners.
335+
336+ Args:
337+ filtered_ledger: The filtered ledger data for all miners
338+
339+ Returns:
340+ dict with structure: {hotkey: {subcategory: {date: return_value}}}
341+ """
342+ subcategory_daily_returns = {}
343+
344+ # Get asset subcategories
345+ asset_class_breakdown = ValiConfig .ASSET_CLASS_BREAKDOWN
346+ asset_subcategories = AssetSegmentation .distill_asset_subcategories (asset_class_breakdown )
347+
348+ segmentation_machine = AssetSegmentation (filtered_ledger )
349+
350+ # Calculate returns for each subcategory
351+ for subcategory in asset_subcategories :
352+ subcategory_ledger = segmentation_machine .segmentation (subcategory )
353+
354+ # Calculate daily returns for each miner in this subcategory
355+ for hotkey , aggregated_ledger in subcategory_ledger .items ():
356+ if hotkey not in subcategory_daily_returns :
357+ subcategory_daily_returns [hotkey ] = {}
358+
359+ # Use the daily_returns_by_date_json function from LedgerUtils
360+ daily_returns = LedgerUtils .daily_returns_by_date_json (aggregated_ledger )
361+ subcategory_daily_returns [hotkey ][subcategory ] = daily_returns
362+
363+ return subcategory_daily_returns
364+
331365 # -------------------------------------------
332366 # Challenge Period
333367 # -------------------------------------------
@@ -620,6 +654,7 @@ def generate_miner_statistics_data(
620654
621655 # For visualization
622656 daily_returns_dict = self .calculate_all_daily_returns (filtered_ledger )
657+ subcategory_daily_returns_dict = self .calculate_subcategory_daily_returns (filtered_ledger )
623658
624659 # Also compute penalty breakdown (for display in final "penalties" dict).
625660 penalty_breakdown = self .calculate_penalties_breakdown (miner_data )
@@ -721,6 +756,9 @@ def build_scores_dict(metric_set: Dict[str, Dict[str, ScoreResult]]) -> Dict[str
721756
722757 # Asset Subcategory Detailed Metrics
723758 asset_subcategory_metrics = self .miner_subcategory_metrics (hotkey , asset_detailed_scores )
759+
760+ # Asset Subcategory Daily Returns
761+ asset_subcategory_daily_returns = subcategory_daily_returns_dict .get (hotkey , {})
724762
725763 final_miner_dict = {
726764 "hotkey" : hotkey ,
@@ -735,6 +773,7 @@ def build_scores_dict(metric_set: Dict[str, Dict[str, ScoreResult]]) -> Dict[str
735773 "risk_profile" : risk_profile_single_dict ,
736774 "asset_subcategory_performance" : asset_subcategory_performance ,
737775 "asset_subcategory_metrics" : asset_subcategory_metrics ,
776+ "asset_subcategory_daily_returns" : asset_subcategory_daily_returns ,
738777 "penalties" : {
739778 "drawdown_threshold" : pen_break .get ("drawdown_threshold" , 1.0 ),
740779 "risk_profile" : pen_break .get ("risk_profile" , 1.0 ),
0 commit comments