Skip to content

Commit 565afdf

Browse files
committed
Fix settings validation asset drift
1 parent b0826aa commit 565afdf

8 files changed

Lines changed: 120 additions & 319 deletions

File tree

.github/workflows/validate.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,12 @@ jobs:
5959
python3 python/scripts/build_config.py --check
6060
python3 python/scripts/build_config.py
6161
python3 python/scripts/sync_strategy_switch_page_asset.py
62-
git diff --exit-code -- web/strategy-switch-console/page_asset.js web/strategy-switch-console/strategy_profiles_asset.js
62+
git diff --exit-code -- web/strategy-switch-console/page_asset.js web/strategy-switch-console/strategy_profiles_asset.js web/strategy-switch-console/app_css.js web/strategy-switch-console/app_js.js
6363
jq empty web/strategy-switch-console/strategy-profiles.example.json
6464
node --experimental-default-type=module tests/strategy_switch_worker_validation.mjs
6565
sed -n '/<script>/,/<\/script>/p' web/strategy-switch-console/index.html | sed '1d;$d' | node --check --input-type=commonjs
6666
node --check --input-type=module < web/strategy-switch-console/page_asset.js
6767
node --check --input-type=module < web/strategy-switch-console/strategy_profiles_asset.js
68+
node --check --input-type=module < web/strategy-switch-console/app_css.js
69+
node --check --input-type=module < web/strategy-switch-console/app_js.js
6870
node --check --input-type=module < web/strategy-switch-console/worker.js

internal_dependency_matrix.json

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,42 @@
66
"path": "requirements-lock.txt",
77
"package": "crypto-strategies",
88
"source_repo": "CryptoStrategies",
9-
"ref": "198027a0f7889e7411f97de3ed528aa90191e533"
9+
"ref": "2c152cf"
10+
},
11+
{
12+
"consumer_repo": "BinancePlatform",
13+
"path": "requirements-lock.txt",
14+
"package": "quant-platform-kit",
15+
"source_repo": "QuantPlatformKit",
16+
"ref": "86f03fb8e83c0d372f4e1c64cccf3e6da50b8dd4"
1017
},
1118
{
1219
"consumer_repo": "BinancePlatform",
1320
"path": "requirements.txt",
1421
"package": "crypto-strategies",
1522
"source_repo": "CryptoStrategies",
16-
"ref": "198027a0f7889e7411f97de3ed528aa90191e533"
23+
"ref": "2c152cf"
24+
},
25+
{
26+
"consumer_repo": "BinancePlatform",
27+
"path": "requirements.txt",
28+
"package": "quant-platform-kit",
29+
"source_repo": "QuantPlatformKit",
30+
"ref": "86f03fb8e83c0d372f4e1c64cccf3e6da50b8dd4"
1731
},
1832
{
1933
"consumer_repo": "CharlesSchwabPlatform",
2034
"path": "requirements.txt",
2135
"package": "us-equity-strategies",
2236
"source_repo": "UsEquityStrategies",
23-
"ref": "a9546362a27abdfc9cd5184b30ca8d26fd774187"
37+
"ref": "c8df5f9659340965bd7f53998892ed1018ed4254"
38+
},
39+
{
40+
"consumer_repo": "CharlesSchwabPlatform",
41+
"path": "requirements.txt",
42+
"package": "quant-platform-kit",
43+
"source_repo": "QuantPlatformKit",
44+
"ref": "d786c1140967f0e96e35599d057f0655e5a9ba25"
2445
},
2546
{
2647
"consumer_repo": "CnEquitySnapshotPipelines",
@@ -34,21 +55,21 @@
3455
"path": "pyproject.toml",
3556
"package": "quant-platform-kit",
3657
"source_repo": "QuantPlatformKit",
37-
"ref": "d18fe32b57a0a8bb746bebf6f11465dd68107eae"
58+
"ref": "d786c1140967f0e96e35599d057f0655e5a9ba25"
3859
},
3960
{
4061
"consumer_repo": "FirstradePlatform",
41-
"path": "pyproject.toml",
62+
"path": "requirements.txt",
4263
"package": "us-equity-strategies",
4364
"source_repo": "UsEquityStrategies",
44-
"ref": "a9546362a27abdfc9cd5184b30ca8d26fd774187"
65+
"ref": "c8df5f9659340965bd7f53998892ed1018ed4254"
4566
},
4667
{
4768
"consumer_repo": "FirstradePlatform",
4869
"path": "requirements.txt",
49-
"package": "us-equity-strategies",
50-
"source_repo": "UsEquityStrategies",
51-
"ref": "a9546362a27abdfc9cd5184b30ca8d26fd774187"
70+
"package": "quant-platform-kit",
71+
"source_repo": "QuantPlatformKit",
72+
"ref": "d786c1140967f0e96e35599d057f0655e5a9ba25"
5273
},
5374
{
5475
"consumer_repo": "HkEquitySnapshotPipelines",
@@ -62,35 +83,42 @@
6283
"path": "requirements.txt",
6384
"package": "hk-equity-strategies",
6485
"source_repo": "HkEquityStrategies",
65-
"ref": "dbbefb688cd144837aa59581b1930a14c11411ad"
86+
"ref": "700c8b19c46336d3d8fcba687e58553afcf0235f"
6687
},
6788
{
6889
"consumer_repo": "InteractiveBrokersPlatform",
6990
"path": "requirements.txt",
7091
"package": "us-equity-strategies",
7192
"source_repo": "UsEquityStrategies",
72-
"ref": "a9546362a27abdfc9cd5184b30ca8d26fd774187"
93+
"ref": "c8df5f9659340965bd7f53998892ed1018ed4254"
94+
},
95+
{
96+
"consumer_repo": "InteractiveBrokersPlatform",
97+
"path": "requirements.txt",
98+
"package": "quant-platform-kit",
99+
"source_repo": "QuantPlatformKit",
100+
"ref": "d786c1140967f0e96e35599d057f0655e5a9ba25"
73101
},
74102
{
75103
"consumer_repo": "LongBridgePlatform",
76104
"path": "requirements.txt",
77105
"package": "hk-equity-strategies",
78106
"source_repo": "HkEquityStrategies",
79-
"ref": "dbbefb688cd144837aa59581b1930a14c11411ad"
107+
"ref": "700c8b19c46336d3d8fcba687e58553afcf0235f"
80108
},
81109
{
82110
"consumer_repo": "LongBridgePlatform",
83111
"path": "requirements.txt",
84112
"package": "quant-platform-kit",
85113
"source_repo": "QuantPlatformKit",
86-
"ref": "dfdbef6b58ab46f357d67800510bb9e8c4a01182"
114+
"ref": "d786c1140967f0e96e35599d057f0655e5a9ba25"
87115
},
88116
{
89117
"consumer_repo": "LongBridgePlatform",
90118
"path": "requirements.txt",
91119
"package": "us-equity-strategies",
92120
"source_repo": "UsEquityStrategies",
93-
"ref": "a9546362a27abdfc9cd5184b30ca8d26fd774187"
121+
"ref": "c8df5f9659340965bd7f53998892ed1018ed4254"
94122
},
95123
{
96124
"consumer_repo": "QmtPlatform",
@@ -99,6 +127,13 @@
99127
"source_repo": "CnEquityStrategies",
100128
"ref": "357dba7e8896a7f488a484d4a3eea33894708ab9"
101129
},
130+
{
131+
"consumer_repo": "QmtPlatform",
132+
"path": "pyproject.toml",
133+
"package": "quant-platform-kit",
134+
"source_repo": "QuantPlatformKit",
135+
"ref": "e86554b"
136+
},
102137
{
103138
"consumer_repo": "UsEquitySnapshotPipelines",
104139
"path": "pyproject.toml",
@@ -111,7 +146,14 @@
111146
"path": "pyproject.toml",
112147
"package": "us-equity-strategies",
113148
"source_repo": "UsEquityStrategies",
114-
"ref": "a9546362a27abdfc9cd5184b30ca8d26fd774187"
149+
"ref": "c8df5f9659340965bd7f53998892ed1018ed4254"
150+
},
151+
{
152+
"consumer_repo": "UsEquitySnapshotPipelines",
153+
"path": "pyproject.toml",
154+
"package": "quant-platform-kit",
155+
"source_repo": "QuantPlatformKit",
156+
"ref": "d786c1140967f0e96e35599d057f0655e5a9ba25"
115157
}
116158
]
117159
}

python/scripts/sync_strategy_switch_page_asset.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
TARGET = ROOT / "web" / "strategy-switch-console" / "page_asset.js"
1313
PROFILE_SOURCE = ROOT / "web" / "strategy-switch-console" / "strategy-profiles.example.json"
1414
PROFILE_TARGET = ROOT / "web" / "strategy-switch-console" / "strategy_profiles_asset.js"
15+
APP_CSS_SOURCE = ROOT / "web" / "strategy-switch-console" / "app.css"
16+
APP_CSS_TARGET = ROOT / "web" / "strategy-switch-console" / "app_css.js"
17+
APP_JS_SOURCE = ROOT / "web" / "strategy-switch-console" / "app.js"
18+
APP_JS_TARGET = ROOT / "web" / "strategy-switch-console" / "app_js.js"
1519

1620

1721
def main() -> int:
@@ -28,6 +32,20 @@ def main() -> int:
2832
f"export const DEFAULT_STRATEGY_PROFILES = {json.dumps(profiles, ensure_ascii=False)};\n"
2933
)
3034
PROFILE_TARGET.write_text(profile_payload, encoding="utf-8")
35+
36+
app_css = APP_CSS_SOURCE.read_text(encoding="utf-8")
37+
APP_CSS_TARGET.write_text(
38+
"// Generated — CSS asset\n"
39+
f"export const APP_CSS = {json.dumps(app_css, ensure_ascii=False)};\n",
40+
encoding="utf-8",
41+
)
42+
43+
app_js = APP_JS_SOURCE.read_text(encoding="utf-8")
44+
APP_JS_TARGET.write_text(
45+
"// Generated — JS asset\n"
46+
f"export const APP_JS = {json.dumps(app_js, ensure_ascii=False)};\n",
47+
encoding="utf-8",
48+
)
3149
return 0
3250

3351

tests/strategy_switch_worker_validation.mjs

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ import { dirname, resolve } from "node:path";
66
import worker, { __test } from "../web/strategy-switch-console/worker.js";
77

88
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
9-
const indexHtml = readFileSync(resolve(root, "web/strategy-switch-console/index.html"), "utf8");
9+
const indexHtml = [
10+
readFileSync(resolve(root, "web/strategy-switch-console/index.html"), "utf8"),
11+
readFileSync(resolve(root, "web/strategy-switch-console/app.css"), "utf8"),
12+
readFileSync(resolve(root, "web/strategy-switch-console/app.js"), "utf8"),
13+
].join("\n");
1014
assert.ok(__test.currentStrategiesTimeoutMs >= 8000);
1115
const renderPlatformsBody = indexHtml.match(/function renderPlatforms\(\) \{([\s\S]*?)\n \}/)?.[1] || "";
1216
assert.ok(!renderPlatformsBody.includes("syncStrategyForAccount("));
@@ -58,12 +62,12 @@ assert.ok(indexHtml.includes('labelNode.className = "summary-label"'));
5862
assert.equal(indexHtml.includes("noChangesNote"), false);
5963
assert.equal(indexHtml.match(/class="form-section dca-section"/g)?.length, 1);
6064
assert.ok(indexHtml.includes('qmtDryRunOnlyNote'));
61-
assert.ok(indexHtml.includes('optionOverlayDefaultSimple: "策略默认:开启"'));
62-
assert.ok(indexHtml.includes('cashOnlyExecutionDefault: "平台默认:仅用现金"'));
65+
assert.ok(indexHtml.includes('optionOverlayDefaultSimple: "开启"'));
66+
assert.ok(indexHtml.includes('cashOnlyExecutionDefault: "仅用现金"'));
6367
assert.match(indexHtml, /function platformCashOnlyExecutionDefault\(\) \{\s+return true;/);
6468
assert.ok(indexHtml.includes("function effectiveOptionOverlayForAccount("));
6569
assert.ok(indexHtml.includes("function effectiveCashOnlyExecutionForAccount("));
66-
assert.ok(indexHtml.includes('cashOnlyExecutionValueYes: "允许融资:是"'));
70+
assert.ok(indexHtml.includes('cashOnlyExecutionValueYes: "是"'));
6771
assert.ok(indexHtml.includes('cashOnlyExecutionMode: "Allow margin"'));
6872
assert.ok(indexHtml.includes('el("cash-only-execution-mode-select").addEventListener("change"'));
6973
assert.ok(indexHtml.includes("function pendingCashOnlyExecution("));
@@ -161,11 +165,19 @@ assert.match(indexHtml, /body\.app-loading \.shell\s*\{\s*display: none;/);
161165
const servedPageResponse = await worker.fetch(new Request("https://switch.example/"), {});
162166
const servedHtml = await servedPageResponse.text();
163167
assert.equal(servedPageResponse.status, 200);
164-
assert.ok(servedHtml.includes("function hasPrivateConfig()"));
165168
assert.equal(servedHtml.includes("ibkr-primary"), false);
166169
assert.equal(servedHtml.includes("longbridge-quant-sg-service"), false);
167170
assert.equal(servedHtml.includes('account_selector: "SG"'), false);
168171

172+
const servedAppResponse = await worker.fetch(new Request("https://switch.example/app.js"), {});
173+
const servedAppJs = await servedAppResponse.text();
174+
assert.equal(servedAppResponse.status, 200);
175+
assert.ok(servedAppJs.includes("function hasPrivateConfig()"));
176+
assert.ok(servedAppJs.includes("changes.ibitZscoreExitChanged"));
177+
assert.equal(servedAppJs.includes("ibkr-primary"), false);
178+
assert.equal(servedAppJs.includes("longbridge-quant-sg-service"), false);
179+
assert.equal(servedAppJs.includes('account_selector: "SG"'), false);
180+
169181
const publicConfigResponse = await worker.fetch(new Request("https://switch.example/api/config"), {});
170182
assert.equal(publicConfigResponse.status, 200);
171183
const publicConfig = await publicConfigResponse.json();
@@ -559,6 +571,7 @@ assert.equal(normalizedDcaInputs.dca_base_investment_usd, undefined);
559571
assert.deepEqual(JSON.parse(normalizedDcaInputs.extra_variables_json), {
560572
dca_mode: "smart",
561573
dca_base_investment_usd: "500",
574+
cash_only_execution_mode: "enabled",
562575
});
563576
assert.throws(
564577
() => __test.normalizeSwitchInputs({
@@ -570,7 +583,7 @@ assert.throws(
570583
dca_mode: "smart",
571584
dca_base_investment_usd: "500",
572585
}),
573-
/DCA strategy profiles are only supported on firstrade/,
586+
/DCA strategy profiles are not supported on ibkr/,
574587
);
575588
const normalizedDcaJsonInputs = __test.normalizeSwitchInputs({
576589
platform: "firstrade",
@@ -586,6 +599,7 @@ const normalizedDcaJsonInputs = __test.normalizeSwitchInputs({
586599
assert.deepEqual(JSON.parse(normalizedDcaJsonInputs.extra_variables_json), {
587600
dca_mode: "smart",
588601
dca_base_investment_usd: "500",
602+
cash_only_execution_mode: "enabled",
589603
});
590604
const normalizedIbitZscoreInputs = __test.normalizeSwitchInputs({
591605
platform: "firstrade",
@@ -597,6 +611,7 @@ const normalizedIbitZscoreInputs = __test.normalizeSwitchInputs({
597611
});
598612
assert.deepEqual(JSON.parse(normalizedIbitZscoreInputs.extra_variables_json), {
599613
ibit_zscore_exit_mode: "live",
614+
cash_only_execution_mode: "enabled",
600615
});
601616
assert.throws(
602617
() => __test.normalizeSwitchInputs({
@@ -607,7 +622,7 @@ assert.throws(
607622
plugin_mode: "auto",
608623
ibit_zscore_exit_mode: "live",
609624
}),
610-
/DCA strategy profiles are only supported on firstrade/,
625+
/DCA strategy profiles are not supported on ibkr/,
611626
);
612627
assert.throws(
613628
() => __test.normalizeSwitchInputs({
@@ -616,7 +631,7 @@ assert.throws(
616631
strategy_profile: "nasdaq_sp500_smart_dca",
617632
ibit_zscore_exit_mode: "live",
618633
}),
619-
/DCA strategy profiles are only supported on firstrade/,
634+
/DCA strategy profiles are not supported on ibkr/,
620635
);
621636
assert.throws(
622637
() => __test.normalizeSwitchInputs({
@@ -690,13 +705,11 @@ const normalizedReserveClearInputs = __test.normalizeSwitchInputs({
690705
IBKR_RESERVED_CASH_RATIO: "",
691706
}),
692707
});
693-
assert.equal(
694-
normalizedReserveClearInputs.extra_variables_json,
695-
JSON.stringify({
696-
IBKR_MIN_RESERVED_CASH_USD: "",
697-
IBKR_RESERVED_CASH_RATIO: "",
698-
}),
699-
);
708+
assert.deepEqual(JSON.parse(normalizedReserveClearInputs.extra_variables_json), {
709+
IBKR_MIN_RESERVED_CASH_USD: "",
710+
IBKR_RESERVED_CASH_RATIO: "",
711+
cash_only_execution_mode: "enabled",
712+
});
700713
assert.throws(
701714
() => __test.normalizeSwitchInputs({
702715
platform: "ibkr",

web/strategy-switch-console/app.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2105,6 +2105,7 @@ function hasValidStrategySelection(platform = state.selected) {
21052105
optionOverlayChanged: optionOverlay.changed,
21062106
cashOnlyChanged: cashOnly.changed,
21072107
dcaChanged: dca.changed,
2108+
ibitZscoreExitChanged: ibitZscoreExit.changed,
21082109
runtimeTarget,
21092110
reserve,
21102111
income,
@@ -2126,7 +2127,8 @@ function hasValidStrategySelection(platform = state.selected) {
21262127
changes.incomeLayerChanged ||
21272128
changes.optionOverlayChanged ||
21282129
changes.cashOnlyChanged ||
2129-
changes.dcaChanged,
2130+
changes.dcaChanged ||
2131+
changes.ibitZscoreExitChanged,
21302132
);
21312133
}
21322134

@@ -2198,6 +2200,9 @@ function hasValidStrategySelection(platform = state.selected) {
21982200
if (dcaSupported(inputs.strategy_profile)) {
21992201
rows.push([t("currentDca"), currentDcaText(state.selected, account, inputs.strategy_profile)]);
22002202
}
2203+
if (ibitZscoreExitSupported(inputs.strategy_profile)) {
2204+
rows.push([t("currentIbitZscoreExit"), currentIbitZscoreExitText(state.selected, account, inputs.strategy_profile)]);
2205+
}
22012206

22022207
if (changes.reserveCashChanged) {
22032208
rows.push([t("pendingReservedCashPolicy"), pendingReservedCashPolicyText(inputs, state.selected, account), "pending"]);
@@ -2214,7 +2219,10 @@ function hasValidStrategySelection(platform = state.selected) {
22142219
if (changes.dcaChanged) {
22152220
rows.push([t("pendingDca"), pendingDcaText(inputs, state.selected, account), "pending"]);
22162221
}
2217-
2222+
if (changes.ibitZscoreExitChanged) {
2223+
rows.push([t("pendingIbitZscoreExit"), pendingIbitZscoreExitText(inputs, state.selected, account), "pending"]);
2224+
}
2225+
22182226
if (changes.modeChanged) {
22192227
rows.push([t("pendingMode"), modeLabel(inputs.execution_mode), "pending"]);
22202228
}
@@ -3051,4 +3059,3 @@ function hasValidStrategySelection(platform = state.selected) {
30513059
await refreshStrategyProfiles();
30523060
await refreshSession();
30533061
}
3054-

web/strategy-switch-console/app_js.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

web/strategy-switch-console/page_asset.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)