@@ -902,12 +902,54 @@ def get_daily_data(
902902
903903 # Normalize code (strip SH/SZ prefix etc.)
904904 stock_code = normalize_stock_code (stock_code )
905+ should_retry_with_akshare_ambiguous_fallback = (
906+ stock_code .isdigit () and len (stock_code ) == 5
907+ )
905908
906909 fetchers = self ._get_fetchers_snapshot ()
907910 errors = []
908911 total_fetchers = len (fetchers )
909912 request_start = time .time ()
910913
914+ def _run_fetcher_chain (target_code : str , log_prefix : str = "数据源" ) -> Tuple [Optional [pd .DataFrame ], Optional [str ], List [str ], bool ]:
915+ local_errors : List [str ] = []
916+ for attempt , fetcher in enumerate (fetchers , start = 1 ):
917+ try :
918+ logger .info (f"[{ log_prefix } 尝试 { attempt } /{ total_fetchers } ] [{ fetcher .name } ] 获取 { target_code } ..." )
919+ df = self ._call_fetcher_method (
920+ fetcher ,
921+ "get_daily_data" ,
922+ stock_code = target_code ,
923+ start_date = start_date ,
924+ end_date = end_date ,
925+ days = days ,
926+ )
927+
928+ if df is not None and not df .empty :
929+ elapsed = time .time () - request_start
930+ logger .info (
931+ f"[{ log_prefix } 完成] { target_code } 使用 [{ fetcher .name } ] 获取成功: "
932+ f"rows={ len (df )} , elapsed={ elapsed :.2f} s"
933+ )
934+ return df , fetcher .name , local_errors , False
935+
936+ except Exception as e :
937+ error_type , error_reason = summarize_exception (e )
938+ error_msg = f"[{ fetcher .name } ] ({ error_type } ) { error_reason } "
939+ logger .warning (
940+ f"[{ log_prefix } 失败 { attempt } /{ total_fetchers } ] [{ fetcher .name } ] { target_code } : "
941+ f"error_type={ error_type } , reason={ error_reason } "
942+ )
943+ local_errors .append (error_msg )
944+ if attempt < total_fetchers :
945+ next_fetcher = fetchers [attempt ]
946+ if log_prefix == "数据源" :
947+ logger .info (f"[数据源切换] { target_code } : [{ fetcher .name } ] -> [{ next_fetcher .name } ]" )
948+ else :
949+ logger .info (f"[{ log_prefix } 切换] { target_code } : [{ fetcher .name } ] -> [{ next_fetcher .name } ]" )
950+
951+ return None , None , local_errors , True
952+
911953 # 快速路径:美股指数与美股股票直接路由到 YfinanceFetcher
912954 if is_us_index_code (stock_code ) or is_us_stock_code (stock_code ):
913955 for attempt , fetcher in enumerate (fetchers , start = 1 ):
@@ -947,39 +989,24 @@ def get_daily_data(
947989 logger .error (f"[数据源终止] { stock_code } 获取失败: elapsed={ elapsed :.2f} s\n { error_summary } " )
948990 raise DataFetchError (error_summary )
949991
950- for attempt , fetcher in enumerate ( fetchers , start = 1 ):
951- try :
952- logger . info ( f"[数据源尝试 { attempt } / { total_fetchers } ] [ { fetcher . name } ] 获取 { stock_code } ..." )
953- df = self . _call_fetcher_method (
954- fetcher ,
955- "get_daily_data" ,
956- stock_code = stock_code ,
957- start_date = start_date ,
958- end_date = end_date ,
959- days = days
992+ df , source_name , chain_errors , _ = _run_fetcher_chain ( stock_code )
993+ if df is not None :
994+ return df , source_name
995+ errors . extend ( chain_errors )
996+
997+ if should_retry_with_akshare_ambiguous_fallback :
998+ fallback_stock_code = stock_code . zfill ( 6 )
999+ if fallback_stock_code != stock_code :
1000+ logger . info (
1001+ f"[数据源回退] { stock_code } 首轮无可用数据,尝试补零后按 A 股路径重试 { fallback_stock_code } "
9601002 )
961-
962- if df is not None and not df .empty :
963- elapsed = time .time () - request_start
964- logger .info (
965- f"[数据源完成] { stock_code } 使用 [{ fetcher .name } ] 获取成功: "
966- f"rows={ len (df )} , elapsed={ elapsed :.2f} s"
967- )
968- return df , fetcher .name
969-
970- except Exception as e :
971- error_type , error_reason = summarize_exception (e )
972- error_msg = f"[{ fetcher .name } ] ({ error_type } ) { error_reason } "
973- logger .warning (
974- f"[数据源失败 { attempt } /{ total_fetchers } ] [{ fetcher .name } ] { stock_code } : "
975- f"error_type={ error_type } , reason={ error_reason } "
1003+ fallback_df , fallback_source_name , fallback_errors , _ = _run_fetcher_chain (
1004+ fallback_stock_code ,
1005+ log_prefix = "数据源回退" ,
9761006 )
977- errors .append (error_msg )
978- if attempt < total_fetchers :
979- next_fetcher = fetchers [attempt ]
980- logger .info (f"[数据源切换] { stock_code } : [{ fetcher .name } ] -> [{ next_fetcher .name } ]" )
981- # 继续尝试下一个数据源
982- continue
1007+ if fallback_df is not None :
1008+ return fallback_df , fallback_source_name
1009+ errors .extend ([f"fallback:{ msg } " for msg in fallback_errors ])
9831010
9841011 # 所有数据源都失败
9851012 error_summary = f"所有数据源获取 { stock_code } 失败:\n " + "\n " .join (errors )
0 commit comments