@@ -97,8 +97,8 @@ pub(crate) enum Command {
9797
9898#[ derive( Debug , Default ) ]
9999struct TradingDays {
100- normal_days : HashMap < Market , HashSet < Date > > ,
101100 half_days : HashMap < Market , HashSet < Date > > ,
101+ fetched : HashSet < Market > ,
102102}
103103
104104impl TradingDays {
@@ -265,8 +265,6 @@ impl Core {
265265 . collect ( ) ;
266266 ws_cli. set_rate_limit ( rate_limit. clone ( ) ) ;
267267
268- let current_trade_days = fetch_trading_days ( & ws_cli) . await ?;
269-
270268 let mut table = Table :: new ( ) ;
271269 for market_packages in quote_package_details_by_market {
272270 if market_packages. warning . is_empty ( ) {
@@ -301,7 +299,7 @@ impl Core {
301299 } ) ;
302300
303301 self . rate_limit = rate_limit;
304- self . trading_days = current_trade_days ;
302+ self . trading_days = TradingDays :: default ( ) ;
305303 self . ws_cli = Some ( ws_cli) ;
306304 self . session = Some ( session) ;
307305 Ok ( ( ) )
@@ -422,10 +420,23 @@ impl Core {
422420 }
423421 }
424422 _ = update_trading_days_interval. tick( ) => {
425- if let Some ( ws_cli) = & self . ws_cli
426- && let Ok ( days) = fetch_trading_days( ws_cli) . await
427- {
428- self . trading_days = days;
423+ if let Some ( ws_cli) = & self . ws_cli {
424+ let markets: Vec <Market > =
425+ self . trading_days. fetched. iter( ) . copied( ) . collect( ) ;
426+ for market in markets {
427+ match fetch_trading_days_for_market( ws_cli, market) . await {
428+ Ok ( half_days) => {
429+ self . trading_days. half_days. insert( market, half_days) ;
430+ }
431+ Err ( err) => {
432+ tracing:: warn!(
433+ market = ?market,
434+ error = %err,
435+ "failed to refresh trading days"
436+ ) ;
437+ }
438+ }
439+ }
429440 }
430441 }
431442 }
@@ -823,7 +834,26 @@ impl Core {
823834 async fn handle_ws_event ( & mut self , event : WsEvent ) -> Result < ( ) > {
824835 match event {
825836 WsEvent :: Error ( err) => Err ( err. into ( ) ) ,
826- WsEvent :: Push { command_code, body } => self . handle_push ( command_code, body) ,
837+ WsEvent :: Push { command_code, body } => self . handle_push ( command_code, body) . await ,
838+ }
839+ }
840+
841+ /// Fetch and cache trading days for `market` if not already fetched.
842+ /// Errors are logged and silently swallowed so a failed fetch never
843+ /// disrupts the push handling path.
844+ async fn ensure_trading_days ( & mut self , market : Market ) {
845+ if self . trading_days . fetched . contains ( & market) {
846+ return ;
847+ }
848+ let Some ( ws_cli) = & self . ws_cli else { return } ;
849+ match fetch_trading_days_for_market ( ws_cli, market) . await {
850+ Ok ( half_days) => {
851+ self . trading_days . half_days . insert ( market, half_days) ;
852+ self . trading_days . fetched . insert ( market) ;
853+ }
854+ Err ( err) => {
855+ tracing:: warn!( market = ?market, error = %err, "failed to fetch trading days" ) ;
856+ }
827857 }
828858 }
829859
@@ -954,7 +984,7 @@ impl Core {
954984 }
955985 }
956986
957- fn handle_push ( & mut self , command_code : u8 , body : Vec < u8 > ) -> Result < ( ) > {
987+ async fn handle_push ( & mut self , command_code : u8 , body : Vec < u8 > ) -> Result < ( ) > {
958988 match PushEvent :: parse ( command_code, & body) {
959989 Ok ( ( mut event, tag) ) => {
960990 tracing:: info!( event = ?event, tag = ?tag, "push event" ) ;
@@ -964,6 +994,9 @@ impl Core {
964994 }
965995
966996 if let PushEventDetail :: Quote ( push_quote) = & event. detail {
997+ if let Some ( market) = parse_market_from_symbol ( & event. symbol ) {
998+ self . ensure_trading_days ( market) . await ;
999+ }
9671000 self . merge_candlesticks_by_quote ( & event. symbol , push_quote) ;
9681001
9691002 if !self
@@ -975,6 +1008,9 @@ impl Core {
9751008 return Ok ( ( ) ) ;
9761009 }
9771010 } else if let PushEventDetail :: Trade ( trades) = & event. detail {
1011+ if let Some ( market) = parse_market_from_symbol ( & event. symbol ) {
1012+ self . ensure_trading_days ( market) . await ;
1013+ }
9781014 self . merge_candlesticks_by_trades ( & event. symbol , trades) ;
9791015
9801016 if !self
@@ -1115,46 +1151,28 @@ fn merge_type(
11151151 } )
11161152}
11171153
1118- async fn fetch_trading_days ( cli : & WsClient ) -> Result < TradingDays > {
1119- let mut days = TradingDays :: default ( ) ;
1154+ async fn fetch_trading_days_for_market ( cli : & WsClient , market : Market ) -> Result < HashSet < Date > > {
11201155 let begin_day = OffsetDateTime :: now_utc ( ) . date ( ) - time:: Duration :: days ( 5 ) ;
11211156 let end_day = begin_day + time:: Duration :: days ( 30 ) ;
11221157
1123- for market in [ Market :: HK , Market :: US , Market :: SG , Market :: CN ] {
1124- let resp = cli
1125- . request :: < _ , MarketTradeDayResponse > (
1126- cmd_code:: GET_TRADING_DAYS ,
1127- None ,
1128- MarketTradeDayRequest {
1129- market : market. to_string ( ) ,
1130- beg_day : format_date ( begin_day) ,
1131- end_day : format_date ( end_day) ,
1132- } ,
1133- )
1134- . await ?;
1135-
1136- days. normal_days . insert (
1137- market,
1138- resp. trade_day
1139- . iter ( )
1140- . map ( |value| {
1141- parse_date ( value) . map_err ( |err| Error :: parse_field_error ( "half_trade_day" , err) )
1142- } )
1143- . collect :: < Result < HashSet < _ > > > ( ) ?,
1144- ) ;
1145-
1146- days. half_days . insert (
1147- market,
1148- resp. half_trade_day
1149- . iter ( )
1150- . map ( |value| {
1151- parse_date ( value) . map_err ( |err| Error :: parse_field_error ( "half_trade_day" , err) )
1152- } )
1153- . collect :: < Result < HashSet < _ > > > ( ) ?,
1154- ) ;
1155- }
1158+ let resp = cli
1159+ . request :: < _ , MarketTradeDayResponse > (
1160+ cmd_code:: GET_TRADING_DAYS ,
1161+ None ,
1162+ MarketTradeDayRequest {
1163+ market : market. to_string ( ) ,
1164+ beg_day : format_date ( begin_day) ,
1165+ end_day : format_date ( end_day) ,
1166+ } ,
1167+ )
1168+ . await ?;
11561169
1157- Ok ( days)
1170+ resp. half_trade_day
1171+ . iter ( )
1172+ . map ( |value| {
1173+ parse_date ( value) . map_err ( |err| Error :: parse_field_error ( "half_trade_day" , err) )
1174+ } )
1175+ . collect ( )
11581176}
11591177
11601178#[ allow( clippy:: too_many_arguments) ]
0 commit comments