refactor: establish standalone application boundary
This commit is contained in:
+6433
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,219 @@
|
||||
<section id="screenerView" class="workspace-view page member-feature-view">
|
||||
<div class="member-gate" hidden><div class="member-gate-icon"><i data-lucide="lock-keyhole"></i></div><div><strong>智能选股仅对会员开放</strong><span>开通会员后可同步因子、生成公式和执行策略。会员状态可从顶部账号标识进入。</span></div></div>
|
||||
<div class="screener-page-bar scr-head">
|
||||
<div class="section-toolbar screener-page-heading">
|
||||
<div class="section-title-group">
|
||||
<h2>智能选股</h2>
|
||||
<span id="screenerDateLabel" class="section-subtitle">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="screener-mode-tabs method" role="tablist" aria-label="智能选股模式">
|
||||
<button class="active" type="button" role="tab" aria-selected="true" data-screener-mode="smart">阶段选股</button>
|
||||
<button type="button" role="tab" aria-selected="false" data-screener-mode="curated">策略选股</button>
|
||||
<button type="button" role="tab" aria-selected="false" data-screener-mode="quant">自定义选股</button>
|
||||
</div>
|
||||
<button id="openScreenerTrackingButton" class="button screener-tracking-entry" type="button"><i data-lucide="chart-no-axes-combined"></i>策略跟踪</button>
|
||||
</div>
|
||||
<div id="screenerNotice" class="inline-notice" hidden></div>
|
||||
<div class="screener-mobile-tabs" role="tablist" aria-label="智能选股视图">
|
||||
<button class="active" type="button" role="tab" aria-selected="true" data-screener-mobile-view="strategy">策略</button>
|
||||
<button type="button" role="tab" aria-selected="false" data-screener-mobile-view="results">候选</button>
|
||||
</div>
|
||||
<div class="screener-strategy-view" data-screener-panel="smart">
|
||||
<div id="screenerProgress" class="screener-stepper stepper" aria-label="智能选股执行进度" aria-live="polite">
|
||||
<div class="screener-step step" data-screener-step="regime"><span class="step-marker no">1</span><div><strong class="tt">阶段识别</strong><small class="ds" id="regimeStepStatus">等待识别</small></div></div>
|
||||
<span class="step-line ln" aria-hidden="true"></span>
|
||||
<div class="screener-step step" data-screener-step="strategy"><span class="step-marker no">2</span><div><strong class="tt">策略匹配</strong><small class="ds" id="strategyStepStatus">等待匹配</small></div></div>
|
||||
<span class="step-line ln" aria-hidden="true"></span>
|
||||
<div class="screener-step step" data-screener-step="run"><span class="step-marker no">3</span><div><strong class="tt">执行选股</strong><small class="ds" id="screenerRunStatus">等待执行</small></div></div>
|
||||
<span class="step-line ln" aria-hidden="true"></span>
|
||||
<div class="screener-step step" data-screener-step="result"><span class="step-marker no">4</span><div><strong class="tt">结果与回测</strong><small class="ds" id="backtestTaskStatus">随选股执行</small></div></div>
|
||||
</div>
|
||||
<div class="screener-overview-grid ps-grid">
|
||||
<section class="screener-overview-card screener-regime-card card">
|
||||
<div class="screener-card-heading card-h"><h3><span>01</span> 当前阶段</h3><span class="screener-soft-label dtag">自动识别已开启</span></div>
|
||||
<div class="screener-regime-body">
|
||||
<div class="regime-summary"><strong id="regimeLabel">--</strong><span id="regimeConfidence">置信度 --</span></div>
|
||||
<div class="regime-reading">
|
||||
<div class="regime-market-line">
|
||||
<div id="regimeEvidenceList" class="regime-evidence-line"></div>
|
||||
</div>
|
||||
<div id="regimeReason" class="regime-advice">--</div>
|
||||
<div class="regime-control-line">
|
||||
<div id="regimeSelector" class="regime-selector" aria-label="系统识别的市场阶段"></div>
|
||||
<div class="factor-data-status"><span>盘后行情定格后自动更新</span><strong id="factorDateCount">0 日</strong><small id="factorDateRange">等待后台数据</small></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="screener-overview-card screener-strategy-card card">
|
||||
<div class="screener-card-heading card-h"><h3><span>02</span> 匹配策略</h3><span class="screener-soft-label dtag">自然语言转受控公式</span></div>
|
||||
<div class="screener-strategy-summary">
|
||||
<div class="screener-strategy-title"><strong id="activeStrategyHeading">--</strong><span id="activeStrategyRegimes"></span></div>
|
||||
<p id="activeStrategyDescription">等待匹配当前市场阶段的策略。</p>
|
||||
<div class="screener-strategy-actions"><span class="screener-auto-note">由系统按当前阶段自动匹配</span></div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="screener-runbar runbar">
|
||||
<div class="screener-run-actions">
|
||||
<button id="screenerExportButton" class="button" type="button">导出 CSV</button>
|
||||
</div>
|
||||
<div class="screener-pipeline-status" aria-live="polite">
|
||||
<span>因子 <strong id="factorTaskStatus">等待检查</strong></span>
|
||||
<span>编译 <strong id="compilerStatus">本地模板编译</strong></span>
|
||||
</div>
|
||||
</div>
|
||||
<div data-screener-results-slot="smart"></div>
|
||||
</div>
|
||||
<div class="curated-screener-panel" data-screener-panel="curated" hidden>
|
||||
<div class="curated-workspace">
|
||||
<aside class="curated-library-pane" aria-label="精选策略库">
|
||||
<div class="curated-library-heading">
|
||||
<div><span>策略库</span><h3>盘后自动候选池</h3></div><strong id="curatedStrategyCount">29 套</strong>
|
||||
</div>
|
||||
<div class="curated-library-controls">
|
||||
<label class="curated-search"><i data-lucide="search"></i><span class="visually-hidden">搜索策略</span><input id="curatedStrategySearch" type="search" placeholder="搜索策略" autocomplete="off"></label>
|
||||
<label class="curated-category-select"><span class="visually-hidden">策略分类</span><select id="curatedCategoryFilter" aria-label="策略分类"></select><i data-lucide="chevron-down"></i></label>
|
||||
<div class="curated-view-toggle" role="group" aria-label="策略排列方式">
|
||||
<button class="active" type="button" data-curated-view="list" aria-label="列表排列" title="列表排列" aria-pressed="true"><i data-lucide="list"></i></button>
|
||||
<button type="button" data-curated-view="grid" aria-label="图标排列" title="图标排列" aria-pressed="false"><i data-lucide="layout-grid"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="curatedSchoolFilters" class="curated-school-filters" aria-label="策略流派"></div>
|
||||
<div id="curatedStrategyList" class="curated-strategy-list"></div>
|
||||
</aside>
|
||||
<section class="curated-detail-pane" aria-labelledby="curatedStrategyName">
|
||||
<header class="curated-detail-header">
|
||||
<div><span id="curatedStrategyCategory">精选策略</span><h3 id="curatedStrategyName">选择一套策略</h3><p id="curatedStrategyDescription">查看策略条件、数据状态和适用环境。</p></div>
|
||||
<div id="curatedStrategyBadges" class="curated-strategy-badges"></div>
|
||||
</header>
|
||||
<div class="curated-environment-notes">
|
||||
<p><strong>适用环境</strong><span id="curatedSuitableEnvironment"></span></p>
|
||||
<p><strong>失效风险</strong><span id="curatedFailureRisk"></span></p>
|
||||
</div>
|
||||
<div class="curated-health-grid" id="curatedHealthMetrics" aria-label="策略运行状态"></div>
|
||||
<div class="curated-detail-grid">
|
||||
<section class="curated-condition-section"><div class="mini-section-heading"><h4>准入条件</h4><span id="curatedFilterCount">0 项</span></div><div id="curatedFilterList" class="curated-rule-list"></div></section>
|
||||
<section class="curated-condition-section"><div class="mini-section-heading"><h4>评分权重</h4><span id="curatedWeightTotal">100%</span></div><div id="curatedScoreList" class="curated-score-list"></div></section>
|
||||
</div>
|
||||
<div class="curated-execution-bar">
|
||||
<div id="curatedDataStatus" class="curated-data-status"><i data-lucide="database"></i><span><strong>检查数据中</strong><small>同步后显示可用状态</small></span></div>
|
||||
<span class="screener-auto-note">候选池由后台盘后自动更新</span>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div data-screener-results-slot="curated"></div>
|
||||
</div>
|
||||
<div class="quant-screener-panel" data-screener-panel="quant" hidden>
|
||||
<section class="custom-screener-tools card">
|
||||
<div><span>自定义能力</span><strong>用自然语言生成公式,或直接编辑受控公式</strong><small>自定义选股仅在点击执行后计算,不影响系统盘后候选池。</small></div>
|
||||
<div>
|
||||
<button id="openStrategyDrawerButton" class="button" type="button"><i data-lucide="sparkles"></i>自然语言生成公式</button>
|
||||
<button id="quantSaveButton" class="button" type="button"><i data-lucide="braces"></i>编辑 / 保存公式</button>
|
||||
</div>
|
||||
</section>
|
||||
<section class="quant-builder-pane">
|
||||
<header class="quant-panel-heading"><h3>因子与权重</h3><div><button id="addQuantScoreButton" class="button" type="button"><i data-lucide="plus"></i>添加因子</button><button id="quantResetButton" class="button ghost" type="button"><i data-lucide="rotate-ccw"></i>重置</button></div></header>
|
||||
<div id="quantScoreRows" class="quant-rule-rows"></div>
|
||||
<div class="quant-weight-status"><span>权重合计</span><div><i id="quantWeightBar"></i></div><strong id="quantWeightTotal">100%</strong></div>
|
||||
</section>
|
||||
<div class="quant-right-stack">
|
||||
<aside class="quant-summary-pane">
|
||||
<header><h3>过滤条件</h3><button id="addQuantFilterButton" class="button ghost" type="button"><i data-lucide="plus"></i>添加条件</button></header>
|
||||
<div class="quant-filter-body">
|
||||
<div class="quant-universe-grid">
|
||||
<strong>选股范围</strong>
|
||||
<label class="form-field"><span>上市不少于</span><input id="quantListedDays" type="number" min="0" max="5000" step="30" value="120"><small>日</small></label>
|
||||
<label class="form-field"><span>输出</span><input id="quantLimit" type="number" min="1" max="50" value="15"><small>只</small></label>
|
||||
<label class="form-field"><span>综合分不低于</span><input id="quantMinScore" type="number" min="0" max="100" step="1" value="50"></label>
|
||||
<label class="checkbox-control quant-st-toggle"><input id="quantExcludeSt" type="checkbox" checked>剔除 ST / 退市</label>
|
||||
</div>
|
||||
<div id="quantFilterRows" class="quant-rule-rows"></div>
|
||||
<div class="quant-execution-actions">
|
||||
<button id="quantRunButton" class="button primary" type="button"><i data-lucide="play"></i>执行自定义选股</button>
|
||||
<label class="checkbox-control"><input id="quantBacktestToggle" type="checkbox" checked>滚动回测</label>
|
||||
<span>结果按加权总分排序,并生成逐股贡献解释</span>
|
||||
</div>
|
||||
<p id="quantValidationMessage" class="quant-validation-message" role="status" aria-live="polite"></p>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
<div class="custom-results-slot" data-screener-results-slot="quant"></div>
|
||||
</div>
|
||||
<div class="screener-results-view">
|
||||
<section id="backtestPanel" class="backtest-panel screener-backtest-strip" hidden>
|
||||
<i data-lucide="triangle-alert" aria-hidden="true"></i>
|
||||
<div id="backtestMetrics" class="dragon-summary"></div>
|
||||
<p id="backtestDefinition">--</p>
|
||||
</section>
|
||||
<div class="section-toolbar result-toolbar">
|
||||
<div class="section-title-group"><h2 id="screenerResultTitle">候选结果</h2><span id="screenerResultCount" class="count-badge">0 只</span><span id="screenerResultSource" class="screener-result-source" hidden></span></div>
|
||||
<span id="screenerDisclaimer" class="section-subtitle">历史统计不代表未来收益</span>
|
||||
</div>
|
||||
<div class="table-frame card tbl-wrap screener-result-frame">
|
||||
<table class="data-table tbl">
|
||||
<colgroup class="screener-result-columns"><col><col><col><col><col><col><col><col><col><col><col><col></colgroup>
|
||||
<thead><tr>
|
||||
<th class="num">排名</th><th>股票</th><th>板块</th><th class="number num sortable">综合分<span class="arr">↕</span></th>
|
||||
<th class="number num sortable">历史估计(%)<span class="arr">↕</span></th><th class="number num sortable">当日涨幅(%)<span class="arr">↕</span></th><th class="number num sortable">5日涨幅(%)<span class="arr">↕</span></th>
|
||||
<th class="number num sortable">量比<span class="arr">↕</span></th><th class="number num sortable">板块强度<span class="arr">↕</span></th><th>主要贡献</th><th>风险</th><th>操作</th>
|
||||
</tr></thead>
|
||||
<tbody id="screenerTableBody"></tbody>
|
||||
</table>
|
||||
<div id="screenerEmpty" class="empty-state">尚未执行选股</div>
|
||||
</div>
|
||||
</div>
|
||||
<dialog id="strategyDrawer" class="strategy-drawer" aria-labelledby="strategyDrawerTitle">
|
||||
<div class="strategy-drawer-header"><div><span>自定义选股</span><h2 id="strategyDrawerTitle">自然语言与受控公式</h2></div><button id="closeStrategyDrawerButton" class="icon-button" type="button" aria-label="关闭策略编辑"><i data-lucide="x"></i></button></div>
|
||||
<div class="strategy-drawer-body">
|
||||
<aside class="strategy-sidebar">
|
||||
<div class="workspace-heading card-h"><h3>策略库</h3><span id="strategyCount">0 套</span></div>
|
||||
<div id="strategyList" class="strategy-list"></div>
|
||||
</aside>
|
||||
<div class="strategy-workbench">
|
||||
<div class="strategy-workbench-heading"><div><span>当前策略</span><h3 id="activeStrategyEditorHeading">--</h3></div><small>自然语言生成受控公式</small></div>
|
||||
<div class="strategy-meta-fields">
|
||||
<label class="form-field"><span>策略名称</span><input id="strategyNameInput" type="text" maxlength="60"></label>
|
||||
<label class="form-field"><span>策略说明</span><input id="strategyDescriptionInput" type="text" maxlength="1000"></label>
|
||||
</div>
|
||||
<label class="form-field strategy-prompt-field"><span>自然语言策略</span><textarea id="strategyPrompt" maxlength="3000" placeholder="例如:修复阶段筛选低吸、放量、有主力资金流入的主线前排"></textarea></label>
|
||||
<div class="strategy-actions">
|
||||
<label class="checkbox-control"><input id="runBacktestToggle" type="checkbox" checked>滚动回测</label>
|
||||
<button id="compileStrategyButton" class="button" type="button">生成公式</button>
|
||||
<button id="saveStrategyButton" class="button primary" type="button">保存策略</button>
|
||||
<button id="deleteStrategyButton" class="button danger-button" type="button" hidden>删除策略</button>
|
||||
</div>
|
||||
<details class="strategy-advanced">
|
||||
<summary><div><strong>高级公式</strong><span>查看或手动调整受控 DSL</span></div><i data-lucide="chevron-down" aria-hidden="true"></i></summary>
|
||||
<label class="form-field formula-field"><span>受控公式 DSL</span><textarea id="formulaEditor" spellcheck="false"></textarea></label>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
</section>
|
||||
<section id="screenerTrackingView" class="workspace-view page member-feature-view screener-tracking-view" data-internal-view>
|
||||
<div class="member-gate" hidden><div class="member-gate-icon"><i data-lucide="lock-keyhole"></i></div><div><strong>策略跟踪仅对会员开放</strong><span>开通会员后可将选股候选加入持续跟踪。</span></div></div>
|
||||
<header class="tracking-page-header">
|
||||
<button id="closeScreenerTrackingButton" class="tracking-back-button" type="button" data-member-navigation><i data-lucide="arrow-left"></i>返回智能选股</button>
|
||||
<div><h2 id="strategyTrackingTitle">策略持续跟踪</h2><p>仅跟踪手动加入的候选,以入选价观察后续五个交易日。</p></div>
|
||||
<button id="refreshTrackingButton" class="button" type="button"><i data-lucide="refresh-cw"></i>更新跟踪</button>
|
||||
</header>
|
||||
<div class="tracking-overview-card">
|
||||
<div class="tracking-overview-title"><span>跟踪概览</span><strong id="trackingBatchCount">0 批</strong></div>
|
||||
<div id="trackingSummary" class="tracking-summary"></div>
|
||||
</div>
|
||||
<section class="strategy-tracking-panel" aria-labelledby="strategyTrackingTitle">
|
||||
<div class="section-toolbar result-toolbar">
|
||||
<div class="section-title-group"><h2>跟踪明细</h2><span class="count-badge">T+5</span></div>
|
||||
<span class="section-subtitle">收益均以加入跟踪时的入选价为基准</span>
|
||||
</div>
|
||||
<div class="table-frame tracking-table-frame">
|
||||
<table class="data-table tbl tracking-table">
|
||||
<thead><tr><th>入选日</th><th>策略</th><th>股票</th><th class="number num">入选价(元)</th><th class="number num">T+1 开(%)</th><th class="number num">T+1 收(%)</th><th class="number num">T+3(%)</th><th class="number num">T+5(%)</th><th class="number num">最大涨幅(%)</th><th class="number num">最大回撤(%)</th><th>状态</th><th>操作</th></tr></thead>
|
||||
<tbody id="trackingTableBody"></tbody>
|
||||
</table>
|
||||
<div id="trackingEmpty" class="empty-state">尚未加入跟踪,请从智能选股候选结果中手动添加。</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
@@ -1,10 +1,10 @@
|
||||
window.XiaobaiPageModules.register("screener", ["screenerView"], {
|
||||
bind: bindScreenerEvents,
|
||||
enter: ["loadScreener"],
|
||||
});
|
||||
|
||||
window.XiaobaiPageModules.register("screener", ["screenerTrackingView"]);
|
||||
|
||||
/* PRESERVATION-SOURCE-BEGIN app.js:3490-4336 */
|
||||
function screenerStrategyKey(strategyId, strategyName) {
|
||||
return strategyId != null && strategyId !== 0 ? `id:${strategyId}` : `name:${strategyName || ""}`;
|
||||
}
|
||||
@@ -841,8 +841,6 @@ async function executeScreenerFormula({ mode, formula, strategyName, strategyId
|
||||
}
|
||||
}
|
||||
|
||||
/* PRESERVATION-SOURCE-END app.js:3490-4336 */
|
||||
/* PRESERVATION-SOURCE-BEGIN app.js:6668-6892 */
|
||||
function renderScreenerResult() {
|
||||
const mode = state.screenerMode || "smart";
|
||||
const result = activeScreenerResult(mode);
|
||||
@@ -1068,4 +1066,74 @@ function regimeLabel(regime) {
|
||||
return state.screenerSetup?.regimes?.find((item) => item.id === regime)?.label || regime;
|
||||
}
|
||||
|
||||
/* PRESERVATION-SOURCE-END app.js:6668-6892 */
|
||||
|
||||
function bindScreenerEvents() {
|
||||
document.querySelector("#openStrategyDrawerButton").addEventListener("click", openCustomStrategyDrawer);
|
||||
document.querySelector("#closeStrategyDrawerButton").addEventListener("click", () => document.querySelector("#strategyDrawer").close());
|
||||
document.querySelector("#strategyDrawer").addEventListener("click", (event) => {
|
||||
if (event.target === event.currentTarget) event.currentTarget.close();
|
||||
});
|
||||
document.querySelector("#openScreenerTrackingButton").addEventListener("click", async () => {
|
||||
await loadScreenerTracking(true);
|
||||
openView("screenerTrackingView");
|
||||
});
|
||||
document.querySelector("#closeScreenerTrackingButton").addEventListener("click", () => openView("screenerView"));
|
||||
document.querySelector("#refreshTrackingButton").addEventListener("click", refreshScreenerTracking);
|
||||
document.querySelector("#trackingTableBody").addEventListener("click", handleTrackingTableAction);
|
||||
document.querySelectorAll("[data-screener-mobile-view]").forEach((button) => {
|
||||
button.addEventListener("click", () => selectScreenerMobileView(button.dataset.screenerMobileView));
|
||||
});
|
||||
document.querySelector("#compileStrategyButton").addEventListener("click", compileStrategy);
|
||||
document.querySelector("#saveStrategyButton").addEventListener("click", saveCurrentStrategy);
|
||||
document.querySelector("#deleteStrategyButton").addEventListener("click", deleteCurrentStrategy);
|
||||
document.querySelector("#screenerExportButton").addEventListener("click", exportScreenerResults);
|
||||
document.querySelector("#runBacktestToggle").addEventListener("change", updateBacktestTaskStatus);
|
||||
document.querySelectorAll("[data-screener-mode]").forEach((button) => {
|
||||
button.addEventListener("click", () => selectScreenerMode(button.dataset.screenerMode));
|
||||
});
|
||||
document.querySelector("#curatedStrategyList").addEventListener("click", (event) => {
|
||||
if (event.target.closest("button")) return;
|
||||
const card = event.target.closest("[data-curated-strategy]");
|
||||
if (!card) return;
|
||||
state.selectedCuratedStrategyId = number(card.dataset.curatedStrategy);
|
||||
renderCuratedStrategyLibrary();
|
||||
renderScreenerResult();
|
||||
});
|
||||
document.querySelector("#curatedStrategySearch").addEventListener("input", (event) => {
|
||||
state.curatedQuery = event.target.value.trim().toLocaleLowerCase("zh-CN");
|
||||
renderCuratedStrategyLibrary();
|
||||
});
|
||||
document.querySelector("#curatedCategoryFilter").addEventListener("change", (event) => {
|
||||
state.curatedCategory = event.target.value;
|
||||
renderCuratedStrategyLibrary();
|
||||
});
|
||||
document.querySelector("#curatedSchoolFilters").addEventListener("click", (event) => {
|
||||
const button = event.target.closest("[data-curated-school]");
|
||||
if (!button) return;
|
||||
state.curatedSchool = button.dataset.curatedSchool;
|
||||
renderCuratedStrategyLibrary();
|
||||
});
|
||||
document.querySelectorAll("[data-curated-view]").forEach((button) => {
|
||||
button.addEventListener("click", () => {
|
||||
state.curatedViewMode = button.dataset.curatedView === "grid" ? "grid" : "list";
|
||||
localStorage.setItem("xiaobaiCuratedViewMode", state.curatedViewMode);
|
||||
renderCuratedStrategyLibrary();
|
||||
});
|
||||
});
|
||||
document.querySelector("#quantResetButton").addEventListener("click", resetQuantBuilder);
|
||||
document.querySelector("#addQuantFilterButton").addEventListener("click", () => addQuantFilter());
|
||||
document.querySelector("#addQuantScoreButton").addEventListener("click", () => addQuantScore());
|
||||
document.querySelector("#quantFilterRows").addEventListener("input", handleQuantBuilderInput);
|
||||
document.querySelector("#quantFilterRows").addEventListener("change", handleQuantBuilderInput);
|
||||
document.querySelector("#quantFilterRows").addEventListener("click", handleQuantBuilderClick);
|
||||
document.querySelector("#quantScoreRows").addEventListener("input", handleQuantBuilderInput);
|
||||
document.querySelector("#quantScoreRows").addEventListener("change", handleQuantBuilderInput);
|
||||
document.querySelector("#quantScoreRows").addEventListener("click", handleQuantBuilderClick);
|
||||
["quantListedDays", "quantLimit", "quantMinScore", "quantExcludeSt"].forEach((id) => {
|
||||
document.querySelector(`#${id}`).addEventListener("input", renderQuantSummary);
|
||||
document.querySelector(`#${id}`).addEventListener("change", renderQuantSummary);
|
||||
});
|
||||
document.querySelector("#quantRunButton").addEventListener("click", runQuantStrategy);
|
||||
document.querySelector("#quantSaveButton").addEventListener("click", saveQuantAsStrategy);
|
||||
document.querySelector("#quantBacktestToggle").addEventListener("change", updateBacktestTaskStatus);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user