From 7f9d40423c1fc7f9fd9b35245ab352d809e2d50e Mon Sep 17 00:00:00 2001
From: Pigbibi <20649888+Pigbibi@users.noreply.github.com>
Date: Wed, 10 Jun 2026 03:04:01 +0800
Subject: [PATCH] Read current reserved cash in switch console
---
tests/strategy_switch_worker_validation.mjs | 56 ++++++++++++
web/strategy-switch-console/index.html | 94 +++++++++++++++++++--
web/strategy-switch-console/page_asset.js | 2 +-
web/strategy-switch-console/worker.js | 67 +++++++++++++++
4 files changed, 210 insertions(+), 9 deletions(-)
diff --git a/tests/strategy_switch_worker_validation.mjs b/tests/strategy_switch_worker_validation.mjs
index fababe2..1106932 100644
--- a/tests/strategy_switch_worker_validation.mjs
+++ b/tests/strategy_switch_worker_validation.mjs
@@ -22,6 +22,9 @@ assert.ok(indexHtml.includes('el("quick-form").hidden = !showPrivateControls'));
assert.ok(indexHtml.includes('id="min-reserved-cash-input"'));
assert.ok(indexHtml.includes('id="reserved-cash-ratio-input"'));
assert.ok(indexHtml.includes('function selectedCashCurrency('));
+assert.ok(indexHtml.includes('function currentReservedCashPolicyText('));
+assert.ok(indexHtml.includes('reservedCashTouched: false'));
+assert.ok(indexHtml.includes('.reserve-ratio-block'));
assert.equal(indexHtml.includes("ibkr-primary"), false);
assert.equal(indexHtml.includes("longbridge-quant-sg-service"), false);
assert.equal(indexHtml.includes('account_selector: "SG"'), false);
@@ -257,6 +260,18 @@ globalThis.fetch = async (url) => {
if (requestUrl.endsWith("/CLOUD_RUN_SERVICE_TARGETS_JSON")) {
return new Response("", { status: 404 });
}
+ if (requestUrl.endsWith("/SCHWAB_MIN_RESERVED_CASH_USD")) {
+ return new Response(JSON.stringify({ value: "150" }), {
+ status: 200,
+ headers: { "Content-Type": "application/json" },
+ });
+ }
+ if (requestUrl.endsWith("/SCHWAB_RESERVED_CASH_RATIO")) {
+ return new Response(JSON.stringify({ value: "0.03" }), {
+ status: 200,
+ headers: { "Content-Type": "application/json" },
+ });
+ }
if (requestUrl.endsWith("/RUNTIME_TARGET_JSON")) {
return new Response(JSON.stringify({
value: JSON.stringify({
@@ -278,11 +293,52 @@ try {
);
assert.equal(currentStrategies.schwab.default.strategy_profile, "soxl_soxx_trend_income");
assert.equal(currentStrategies.schwab.default.execution_mode, "live");
+ assert.equal(currentStrategies.schwab.default.min_reserved_cash_usd, "150");
+ assert.equal(currentStrategies.schwab.default.reserved_cash_ratio, "0.03");
assert.equal(currentStrategies.schwab.default.source, "RUNTIME_TARGET_JSON");
} finally {
globalThis.fetch = originalFetch;
}
+globalThis.fetch = async (url) => {
+ const requestUrl = String(url);
+ if (requestUrl.endsWith("/CLOUD_RUN_SERVICE_TARGETS_JSON")) {
+ return new Response(JSON.stringify({
+ value: JSON.stringify({
+ targets: [
+ {
+ service: "interactive-brokers-demo-ibkr-tqqq-service",
+ ACCOUNT_GROUP: "demo-ibkr-tqqq",
+ IBKR_MIN_RESERVED_CASH_USD: "150",
+ IBKR_RESERVED_CASH_RATIO: "0.03",
+ runtime_target: {
+ platform_id: "ibkr",
+ strategy_profile: "tqqq_growth_income",
+ dry_run_only: false,
+ account_scope: "demo-ibkr-tqqq",
+ service_name: "interactive-brokers-demo-ibkr-tqqq-service",
+ execution_mode: "live",
+ },
+ },
+ ],
+ }),
+ }), { status: 200, headers: { "Content-Type": "application/json" } });
+ }
+ return new Response("", { status: 404 });
+};
+try {
+ const currentStrategies = await __test.loadCurrentStrategies(
+ { ibkr: accountOptions.ibkr },
+ { RUNTIME_SETTINGS_DISPATCH_TOKEN: "test-token" },
+ );
+ assert.equal(currentStrategies.ibkr["ibkr-primary"].strategy_profile, "tqqq_growth_income");
+ assert.equal(currentStrategies.ibkr["ibkr-primary"].min_reserved_cash_usd, "150");
+ assert.equal(currentStrategies.ibkr["ibkr-primary"].reserved_cash_ratio, "0.03");
+ assert.equal(currentStrategies.ibkr["ibkr-primary"].source, "CLOUD_RUN_SERVICE_TARGETS_JSON");
+} finally {
+ globalThis.fetch = originalFetch;
+}
+
const longbridgeHk = __test.assertConfiguredAccount(
{
platform: "longbridge",
diff --git a/web/strategy-switch-console/index.html b/web/strategy-switch-console/index.html
index 4f6ceff..fdda3cf 100644
--- a/web/strategy-switch-console/index.html
+++ b/web/strategy-switch-console/index.html
@@ -407,11 +407,14 @@
.quick-form {
display: grid;
grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
+ align-items: start;
gap: 14px;
}
.control-block {
display: grid;
+ grid-template-rows: auto 48px minmax(20px, auto);
+ align-content: start;
gap: 8px;
min-width: 0;
color: var(--muted);
@@ -419,6 +422,15 @@
font-weight: 760;
}
+ .mode-block {
+ grid-column: 1;
+ }
+
+ .min-reserve-block,
+ .reserve-ratio-block {
+ grid-column: 2;
+ }
+
select,
input {
width: 100%;
@@ -635,6 +647,12 @@
grid-template-columns: 1fr;
}
+ .mode-block,
+ .min-reserve-block,
+ .reserve-ratio-block {
+ grid-column: auto;
+ }
+
.switch-panel {
padding: 18px;
}
@@ -736,7 +754,7 @@
-
+
模式
@@ -744,13 +762,13 @@
-