423423 }
424424
425425 .account-block ,
426- .mode-block {
426+ .mode-block ,
427+ .reserve-policy-block ,
428+ .reserve-ratio-block {
427429 grid-column : 1 / span 2 ;
428430 }
429431
430432 .strategy-block ,
431- .reserve-policy-block {
432- grid-column : 3 / span 2 ;
433- }
434-
433+ .plugin-mode-block ,
435434 .min-reserve-block {
436- grid-column : 1 / span 2 ;
437- }
438-
439- .reserve-ratio-block {
440435 grid-column : 3 / span 2 ;
441436 }
442437
671666 .account-block ,
672667 .strategy-block ,
673668 .mode-block ,
669+ .plugin-mode-block ,
674670 .reserve-policy-block ,
675671 .min-reserve-block ,
676672 .reserve-ratio-block {
@@ -786,6 +782,12 @@ <h2 id="platform-title">LongBridge</h2>
786782 </ div >
787783 </ div >
788784
785+ < label class ="control-block plugin-mode-block ">
786+ < span data-i18n ="pluginMode "> 策略插件</ span >
787+ < select id ="plugin-mode-select "> </ select >
788+ < span class ="selection-meta " data-i18n ="pluginModeMeta "> 控制本次切换是否启用策略插件。</ span >
789+ </ label >
790+
789791 < label class ="control-block reserve-policy-block ">
790792 < span data-i18n ="reservedCashMode "> 预留现金策略</ span >
791793 < select id ="reserve-policy-mode-select "> </ select >
@@ -841,6 +843,7 @@ <h2 data-i18n="summary">切换摘要</h2>
841843 } ;
842844
843845 const reservePolicyModes = [ "current" , "none" , "ratio" , "floor" , "max" ] ;
846+ const pluginModes = [ "auto" , "none" ] ;
844847 const platformMinReservedCashVariables = {
845848 longbridge : "LONGBRIDGE_MIN_RESERVED_CASH_USD" ,
846849 ibkr : "IBKR_MIN_RESERVED_CASH_USD" ,
@@ -906,6 +909,10 @@ <h2 data-i18n="summary">切换摘要</h2>
906909 mode : "模式" ,
907910 live : "实盘" ,
908911 paper : "模拟" ,
912+ pluginMode : "策略插件" ,
913+ pluginModeAuto : "按策略配置启用" ,
914+ pluginModeNone : "禁用插件" ,
915+ pluginModeMeta : "控制本次切换是否启用策略插件。" ,
909916 minReservedCash : "最小预留现金 ({currency})" ,
910917 reservedCashRatio : "预留现金比例" ,
911918 reservedCashMode : "预留现金策略" ,
@@ -942,6 +949,8 @@ <h2 data-i18n="summary">切换摘要</h2>
942949 reservedCashPolicy : "当前预留现金" ,
943950 pendingReservedCashPolicy : "待提交预留现金" ,
944951 pendingMode : "待提交模式" ,
952+ currentPluginMode : "当前插件" ,
953+ pendingPluginMode : "待提交插件" ,
945954 unchanged : "不变" ,
946955 copied : "已复制状态" ,
947956 dispatching : "正在触发 workflow..." ,
@@ -974,6 +983,10 @@ <h2 data-i18n="summary">切换摘要</h2>
974983 mode : "Mode" ,
975984 live : "Live" ,
976985 paper : "Dry run" ,
986+ pluginMode : "Strategy plugins" ,
987+ pluginModeAuto : "Use strategy default" ,
988+ pluginModeNone : "Disable plugins" ,
989+ pluginModeMeta : "Controls whether this switch enables strategy plugins." ,
977990 minReservedCash : "Minimum reserved cash ({currency})" ,
978991 reservedCashRatio : "Reserved cash ratio" ,
979992 reservedCashMode : "Reserved cash policy" ,
@@ -1010,6 +1023,8 @@ <h2 data-i18n="summary">切换摘要</h2>
10101023 reservedCashPolicy : "Current reserved cash" ,
10111024 pendingReservedCashPolicy : "Pending reserved cash" ,
10121025 pendingMode : "Pending mode" ,
1026+ currentPluginMode : "Current plugins" ,
1027+ pendingPluginMode : "Pending plugins" ,
10131028 unchanged : "Unchanged" ,
10141029 copied : "State copied" ,
10151030 dispatching : "Dispatching workflow..." ,
@@ -1048,10 +1063,10 @@ <h2 data-i18n="summary">切换摘要</h2>
10481063 configSource : "default" ,
10491064 repositories : clone ( defaultRepositories ) ,
10501065 forms : {
1051- longbridge : { accountKey : "preview" , strategy : "" , executionMode : "live" , ...defaultReserveForm ( ) } ,
1052- ibkr : { accountKey : "preview" , strategy : "" , executionMode : "live" , ...defaultReserveForm ( ) } ,
1053- schwab : { accountKey : "preview" , strategy : "" , executionMode : "live" , ...defaultReserveForm ( ) } ,
1054- firstrade : { accountKey : "preview" , strategy : "" , executionMode : "live" , ...defaultReserveForm ( ) } ,
1066+ longbridge : { accountKey : "preview" , strategy : "" , executionMode : "live" , pluginMode : "auto" , ...defaultReserveForm ( ) } ,
1067+ ibkr : { accountKey : "preview" , strategy : "" , executionMode : "live" , pluginMode : "auto" , ...defaultReserveForm ( ) } ,
1068+ schwab : { accountKey : "preview" , strategy : "" , executionMode : "live" , pluginMode : "auto" , ...defaultReserveForm ( ) } ,
1069+ firstrade : { accountKey : "preview" , strategy : "" , executionMode : "live" , pluginMode : "auto" , ...defaultReserveForm ( ) } ,
10551070 } ,
10561071 } ;
10571072
@@ -1179,6 +1194,14 @@ <h2 data-i18n="summary">切换摘要</h2>
11791194 return mode === "paper" ? t ( "paper" ) : t ( "live" ) ;
11801195 }
11811196
1197+ function normalizePluginMode ( value ) {
1198+ return pluginModes . includes ( value ) ? value : "auto" ;
1199+ }
1200+
1201+ function pluginModeLabel ( mode ) {
1202+ return mode === "none" ? t ( "pluginModeNone" ) : t ( "pluginModeAuto" ) ;
1203+ }
1204+
11821205 function currentEntryForAccount ( platform , account ) {
11831206 const byPlatform = state . currentStrategies [ platform ] || { } ;
11841207 const keys = [ account ?. key , account ?. target_name , account ?. label ]
@@ -1212,6 +1235,11 @@ <h2 data-i18n="summary">切换摘要</h2>
12121235 return reservePolicyFromEntry ( entry ) ;
12131236 }
12141237
1238+ function currentPluginModeForAccount ( platform , account ) {
1239+ void platform ;
1240+ return normalizePluginMode ( account ?. plugin_mode ) ;
1241+ }
1242+
12151243 function reservePolicyFromEntry ( entry ) {
12161244 return {
12171245 minReservedCashUsd : cleanDisplayNumber ( entry ?. min_reserved_cash_usd ?? entry ?. reserved_cash_floor_usd ) ,
@@ -1291,6 +1319,7 @@ <h2 data-i18n="summary">切换摘要</h2>
12911319 platform ,
12921320 account ,
12931321 ) ;
1322+ state . forms [ platform ] . pluginMode = currentPluginModeForAccount ( platform , account ) ;
12941323 syncReservePolicyForAccount ( platform ) ;
12951324 }
12961325
@@ -1310,6 +1339,7 @@ <h2 data-i18n="summary">切换摘要</h2>
13101339 state . forms [ platform ] . accountKey = options [ 0 ] . key ;
13111340 state . forms [ platform ] . reservedCashTouched = false ;
13121341 state . forms [ platform ] . strategy = defaultStrategyForAccount ( platform , options [ 0 ] , state . forms [ platform ] . strategy ) ;
1342+ state . forms [ platform ] . pluginMode = currentPluginModeForAccount ( platform , options [ 0 ] ) ;
13131343 syncReservePolicyForAccount ( platform ) ;
13141344 }
13151345 }
@@ -1391,7 +1421,7 @@ <h2 data-i18n="summary">切换摘要</h2>
13911421 strategy_profile : form . strategy ,
13921422 execution_mode : form . executionMode ,
13931423 variable_scope : account . variable_scope || "default" ,
1394- plugin_mode : account . plugin_mode || "auto" ,
1424+ plugin_mode : normalizePluginMode ( form . pluginMode ) ,
13951425 service_targets_mode : "auto" ,
13961426 apply : "true" ,
13971427 trigger_platform_sync : "true" ,
@@ -1488,21 +1518,26 @@ <h2 data-i18n="summary">切换摘要</h2>
14881518 const nextProfile = cleanStrategyProfile ( inputs . strategy_profile ) ;
14891519 const currentEntry = currentEntryForAccount ( platform , account ) ;
14901520 const currentMode = normalizeExecutionMode ( currentEntry ?. execution_mode , currentEntry ?. dry_run_only ) ;
1521+ const currentPluginMode = currentPluginModeForAccount ( platform , account ) ;
1522+ const nextPluginMode = normalizePluginMode ( inputs . plugin_mode ) ;
14911523 const reserve = pendingReservePolicy ( inputs , platform , account ) ;
14921524 return {
14931525 currentProfile,
14941526 nextProfile,
14951527 currentMode,
1528+ currentPluginMode,
1529+ nextPluginMode,
14961530 strategyChanged : Boolean ( nextProfile && ( ! currentProfile || currentProfile !== nextProfile ) ) ,
14971531 modeChanged : Boolean ( currentMode && inputs . execution_mode && currentMode !== inputs . execution_mode ) ,
1532+ pluginModeChanged : Boolean ( currentPluginMode && nextPluginMode && currentPluginMode !== nextPluginMode ) ,
14981533 reserveCashChanged : reserve . changed ,
14991534 reserve,
15001535 } ;
15011536 }
15021537
15031538 function hasPendingChanges ( inputs , platform = state . selected , account = selectedAccount ( platform ) ) {
15041539 const changes = pendingChangeState ( inputs , platform , account ) ;
1505- return Boolean ( changes . strategyChanged || changes . modeChanged || changes . reserveCashChanged ) ;
1540+ return Boolean ( changes . strategyChanged || changes . modeChanged || changes . pluginModeChanged || changes . reserveCashChanged ) ;
15061541 }
15071542
15081543 function formatRatioPercent ( value ) {
@@ -1520,6 +1555,7 @@ <h2 data-i18n="summary">切换摘要</h2>
15201555 [ t ( "selectedAccount" ) , account . label ] ,
15211556 [ t ( "currentStrategy" ) , currentStrategyText ] ,
15221557 [ t ( "selectedMarket" ) , supportedDomainLabel ( state . selected , account ) ] ,
1558+ [ t ( "currentPluginMode" ) , pluginModeLabel ( changes . currentPluginMode ) ] ,
15231559 [ t ( "reservedCashPolicy" ) , currentReservedCashPolicyText ( state . selected , account ) ] ,
15241560 ] ;
15251561 if ( changes . reserveCashChanged ) {
@@ -1528,6 +1564,9 @@ <h2 data-i18n="summary">切换摘要</h2>
15281564 if ( changes . modeChanged ) {
15291565 rows . push ( [ t ( "pendingMode" ) , modeLabel ( inputs . execution_mode ) , "pending" ] ) ;
15301566 }
1567+ if ( changes . pluginModeChanged ) {
1568+ rows . push ( [ t ( "pendingPluginMode" ) , pluginModeLabel ( changes . nextPluginMode ) , "pending" ] ) ;
1569+ }
15311570 if ( changes . strategyChanged && changes . nextProfile ) {
15321571 rows . push ( [ t ( "nextStrategy" ) , strategyLabel ( changes . nextProfile ) , "pending" ] ) ;
15331572 }
@@ -1585,6 +1624,7 @@ <h2 data-i18n="summary">切换摘要</h2>
15851624 const choices = strategyChoicesForAccount ( platform , account ) ;
15861625 const accountSelect = el ( "account-select" ) ;
15871626 const strategySelect = el ( "strategy-select" ) ;
1627+ const pluginModeSelect = el ( "plugin-mode-select" ) ;
15881628 const reservePolicyModeSelect = el ( "reserve-policy-mode-select" ) ;
15891629 const minReservedCashInput = el ( "min-reserved-cash-input" ) ;
15901630 const reservedCashRatioInput = el ( "reserved-cash-ratio-input" ) ;
@@ -1600,6 +1640,7 @@ <h2 data-i18n="summary">切换摘要</h2>
16001640 if ( ! showPrivateControls ) {
16011641 accountSelect . replaceChildren ( ) ;
16021642 strategySelect . replaceChildren ( ) ;
1643+ pluginModeSelect . replaceChildren ( ) ;
16031644 reservePolicyModeSelect . replaceChildren ( ) ;
16041645 minReservedCashInput . value = "" ;
16051646 reservedCashRatioInput . value = "" ;
@@ -1633,6 +1674,10 @@ <h2 data-i18n="summary">切换摘要</h2>
16331674 el ( "strategy-meta" ) . textContent = account
16341675 ? t ( "strategyMeta" ) . replace ( "{domains}" , supportedDomainLabel ( platform , account ) )
16351676 : "" ;
1677+ pluginModeSelect . replaceChildren ( ) ;
1678+ for ( const mode of pluginModes ) {
1679+ pluginModeSelect . append ( new Option ( pluginModeLabel ( mode ) , mode , false , mode === normalizePluginMode ( form . pluginMode ) ) ) ;
1680+ }
16361681 reservePolicyModeSelect . replaceChildren ( ) ;
16371682 for ( const mode of reservePolicyModes ) {
16381683 reservePolicyModeSelect . append ( new Option ( t ( `reservePolicy${ mode [ 0 ] . toUpperCase ( ) } ${ mode . slice ( 1 ) } ` ) , mode , false , mode === normalizeReservePolicyMode ( form . reservePolicyMode ) ) ) ;
@@ -1937,6 +1982,11 @@ <h2 data-i18n="summary">切换摘要</h2>
19371982 render ( ) ;
19381983 } ) ;
19391984
1985+ el ( "plugin-mode-select" ) . addEventListener ( "change" , ( ) => {
1986+ state . forms [ state . selected ] . pluginMode = normalizePluginMode ( el ( "plugin-mode-select" ) . value ) ;
1987+ render ( ) ;
1988+ } ) ;
1989+
19401990 el ( "reserve-policy-mode-select" ) . addEventListener ( "change" , ( ) => {
19411991 const form = state . forms [ state . selected ] ;
19421992 form . reservePolicyMode = normalizeReservePolicyMode ( el ( "reserve-policy-mode-select" ) . value ) ;
0 commit comments