Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,12 @@ jobs:
python3 python/scripts/build_config.py --check
python3 python/scripts/build_config.py
python3 python/scripts/sync_strategy_switch_page_asset.py
git diff --exit-code -- web/strategy-switch-console/page_asset.js web/strategy-switch-console/strategy_profiles_asset.js
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
jq empty web/strategy-switch-console/strategy-profiles.example.json
node --experimental-default-type=module tests/strategy_switch_worker_validation.mjs
sed -n '/<script>/,/<\/script>/p' web/strategy-switch-console/index.html | sed '1d;$d' | node --check --input-type=commonjs
node --check --input-type=module < web/strategy-switch-console/page_asset.js
node --check --input-type=module < web/strategy-switch-console/strategy_profiles_asset.js
node --check --input-type=module < web/strategy-switch-console/app_css.js
node --check --input-type=module < web/strategy-switch-console/app_js.js
node --check --input-type=module < web/strategy-switch-console/worker.js
72 changes: 57 additions & 15 deletions internal_dependency_matrix.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,42 @@
"path": "requirements-lock.txt",
"package": "crypto-strategies",
"source_repo": "CryptoStrategies",
"ref": "198027a0f7889e7411f97de3ed528aa90191e533"
"ref": "2c152cf"
},
{
"consumer_repo": "BinancePlatform",
"path": "requirements-lock.txt",
"package": "quant-platform-kit",
"source_repo": "QuantPlatformKit",
"ref": "86f03fb8e83c0d372f4e1c64cccf3e6da50b8dd4"
},
{
"consumer_repo": "BinancePlatform",
"path": "requirements.txt",
"package": "crypto-strategies",
"source_repo": "CryptoStrategies",
"ref": "198027a0f7889e7411f97de3ed528aa90191e533"
"ref": "2c152cf"
},
{
"consumer_repo": "BinancePlatform",
"path": "requirements.txt",
"package": "quant-platform-kit",
"source_repo": "QuantPlatformKit",
"ref": "86f03fb8e83c0d372f4e1c64cccf3e6da50b8dd4"
},
{
"consumer_repo": "CharlesSchwabPlatform",
"path": "requirements.txt",
"package": "us-equity-strategies",
"source_repo": "UsEquityStrategies",
"ref": "a9546362a27abdfc9cd5184b30ca8d26fd774187"
"ref": "c8df5f9659340965bd7f53998892ed1018ed4254"
},
{
"consumer_repo": "CharlesSchwabPlatform",
"path": "requirements.txt",
"package": "quant-platform-kit",
"source_repo": "QuantPlatformKit",
"ref": "d786c1140967f0e96e35599d057f0655e5a9ba25"
},
{
"consumer_repo": "CnEquitySnapshotPipelines",
Expand All @@ -34,21 +55,21 @@
"path": "pyproject.toml",
"package": "quant-platform-kit",
"source_repo": "QuantPlatformKit",
"ref": "d18fe32b57a0a8bb746bebf6f11465dd68107eae"
"ref": "d786c1140967f0e96e35599d057f0655e5a9ba25"
},
{
"consumer_repo": "FirstradePlatform",
"path": "pyproject.toml",
"path": "requirements.txt",
"package": "us-equity-strategies",
"source_repo": "UsEquityStrategies",
"ref": "a9546362a27abdfc9cd5184b30ca8d26fd774187"
"ref": "c8df5f9659340965bd7f53998892ed1018ed4254"
},
{
"consumer_repo": "FirstradePlatform",
"path": "requirements.txt",
"package": "us-equity-strategies",
"source_repo": "UsEquityStrategies",
"ref": "a9546362a27abdfc9cd5184b30ca8d26fd774187"
"package": "quant-platform-kit",
"source_repo": "QuantPlatformKit",
"ref": "d786c1140967f0e96e35599d057f0655e5a9ba25"
},
{
"consumer_repo": "HkEquitySnapshotPipelines",
Expand All @@ -62,35 +83,42 @@
"path": "requirements.txt",
"package": "hk-equity-strategies",
"source_repo": "HkEquityStrategies",
"ref": "dbbefb688cd144837aa59581b1930a14c11411ad"
"ref": "700c8b19c46336d3d8fcba687e58553afcf0235f"
},
{
"consumer_repo": "InteractiveBrokersPlatform",
"path": "requirements.txt",
"package": "us-equity-strategies",
"source_repo": "UsEquityStrategies",
"ref": "a9546362a27abdfc9cd5184b30ca8d26fd774187"
"ref": "c8df5f9659340965bd7f53998892ed1018ed4254"
},
{
"consumer_repo": "InteractiveBrokersPlatform",
"path": "requirements.txt",
"package": "quant-platform-kit",
"source_repo": "QuantPlatformKit",
"ref": "d786c1140967f0e96e35599d057f0655e5a9ba25"
},
{
"consumer_repo": "LongBridgePlatform",
"path": "requirements.txt",
"package": "hk-equity-strategies",
"source_repo": "HkEquityStrategies",
"ref": "dbbefb688cd144837aa59581b1930a14c11411ad"
"ref": "700c8b19c46336d3d8fcba687e58553afcf0235f"
},
{
"consumer_repo": "LongBridgePlatform",
"path": "requirements.txt",
"package": "quant-platform-kit",
"source_repo": "QuantPlatformKit",
"ref": "dfdbef6b58ab46f357d67800510bb9e8c4a01182"
"ref": "d786c1140967f0e96e35599d057f0655e5a9ba25"
},
{
"consumer_repo": "LongBridgePlatform",
"path": "requirements.txt",
"package": "us-equity-strategies",
"source_repo": "UsEquityStrategies",
"ref": "a9546362a27abdfc9cd5184b30ca8d26fd774187"
"ref": "c8df5f9659340965bd7f53998892ed1018ed4254"
},
{
"consumer_repo": "QmtPlatform",
Expand All @@ -99,6 +127,13 @@
"source_repo": "CnEquityStrategies",
"ref": "357dba7e8896a7f488a484d4a3eea33894708ab9"
},
{
"consumer_repo": "QmtPlatform",
"path": "pyproject.toml",
"package": "quant-platform-kit",
"source_repo": "QuantPlatformKit",
"ref": "e86554b"
},
{
"consumer_repo": "UsEquitySnapshotPipelines",
"path": "pyproject.toml",
Expand All @@ -111,7 +146,14 @@
"path": "pyproject.toml",
"package": "us-equity-strategies",
"source_repo": "UsEquityStrategies",
"ref": "a9546362a27abdfc9cd5184b30ca8d26fd774187"
"ref": "c8df5f9659340965bd7f53998892ed1018ed4254"
},
{
"consumer_repo": "UsEquitySnapshotPipelines",
"path": "pyproject.toml",
"package": "quant-platform-kit",
"source_repo": "QuantPlatformKit",
"ref": "d786c1140967f0e96e35599d057f0655e5a9ba25"
}
]
}
18 changes: 18 additions & 0 deletions python/scripts/sync_strategy_switch_page_asset.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
TARGET = ROOT / "web" / "strategy-switch-console" / "page_asset.js"
PROFILE_SOURCE = ROOT / "web" / "strategy-switch-console" / "strategy-profiles.example.json"
PROFILE_TARGET = ROOT / "web" / "strategy-switch-console" / "strategy_profiles_asset.js"
APP_CSS_SOURCE = ROOT / "web" / "strategy-switch-console" / "app.css"
APP_CSS_TARGET = ROOT / "web" / "strategy-switch-console" / "app_css.js"
APP_JS_SOURCE = ROOT / "web" / "strategy-switch-console" / "app.js"
APP_JS_TARGET = ROOT / "web" / "strategy-switch-console" / "app_js.js"


def main() -> int:
Expand All @@ -28,6 +32,20 @@ def main() -> int:
f"export const DEFAULT_STRATEGY_PROFILES = {json.dumps(profiles, ensure_ascii=False)};\n"
)
PROFILE_TARGET.write_text(profile_payload, encoding="utf-8")

app_css = APP_CSS_SOURCE.read_text(encoding="utf-8")
APP_CSS_TARGET.write_text(
"// Generated — CSS asset\n"
f"export const APP_CSS = {json.dumps(app_css, ensure_ascii=False)};\n",
encoding="utf-8",
)

app_js = APP_JS_SOURCE.read_text(encoding="utf-8")
APP_JS_TARGET.write_text(
"// Generated — JS asset\n"
f"export const APP_JS = {json.dumps(app_js, ensure_ascii=False)};\n",
encoding="utf-8",
)
return 0


Expand Down
43 changes: 28 additions & 15 deletions tests/strategy_switch_worker_validation.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ import { dirname, resolve } from "node:path";
import worker, { __test } from "../web/strategy-switch-console/worker.js";

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

const servedAppResponse = await worker.fetch(new Request("https://switch.example/app.js"), {});
const servedAppJs = await servedAppResponse.text();
assert.equal(servedAppResponse.status, 200);
assert.ok(servedAppJs.includes("function hasPrivateConfig()"));
assert.ok(servedAppJs.includes("changes.ibitZscoreExitChanged"));
assert.equal(servedAppJs.includes("ibkr-primary"), false);
assert.equal(servedAppJs.includes("longbridge-quant-sg-service"), false);
assert.equal(servedAppJs.includes('account_selector: "SG"'), false);

const publicConfigResponse = await worker.fetch(new Request("https://switch.example/api/config"), {});
assert.equal(publicConfigResponse.status, 200);
const publicConfig = await publicConfigResponse.json();
Expand Down Expand Up @@ -559,6 +571,7 @@ assert.equal(normalizedDcaInputs.dca_base_investment_usd, undefined);
assert.deepEqual(JSON.parse(normalizedDcaInputs.extra_variables_json), {
dca_mode: "smart",
dca_base_investment_usd: "500",
cash_only_execution_mode: "enabled",
});
assert.throws(
() => __test.normalizeSwitchInputs({
Expand All @@ -570,7 +583,7 @@ assert.throws(
dca_mode: "smart",
dca_base_investment_usd: "500",
}),
/DCA strategy profiles are only supported on firstrade/,
/DCA strategy profiles are not supported on ibkr/,
);
const normalizedDcaJsonInputs = __test.normalizeSwitchInputs({
platform: "firstrade",
Expand All @@ -586,6 +599,7 @@ const normalizedDcaJsonInputs = __test.normalizeSwitchInputs({
assert.deepEqual(JSON.parse(normalizedDcaJsonInputs.extra_variables_json), {
dca_mode: "smart",
dca_base_investment_usd: "500",
cash_only_execution_mode: "enabled",
});
const normalizedIbitZscoreInputs = __test.normalizeSwitchInputs({
platform: "firstrade",
Expand All @@ -597,6 +611,7 @@ const normalizedIbitZscoreInputs = __test.normalizeSwitchInputs({
});
assert.deepEqual(JSON.parse(normalizedIbitZscoreInputs.extra_variables_json), {
ibit_zscore_exit_mode: "live",
cash_only_execution_mode: "enabled",
});
assert.throws(
() => __test.normalizeSwitchInputs({
Expand All @@ -607,7 +622,7 @@ assert.throws(
plugin_mode: "auto",
ibit_zscore_exit_mode: "live",
}),
/DCA strategy profiles are only supported on firstrade/,
/DCA strategy profiles are not supported on ibkr/,
);
assert.throws(
() => __test.normalizeSwitchInputs({
Expand All @@ -616,7 +631,7 @@ assert.throws(
strategy_profile: "nasdaq_sp500_smart_dca",
ibit_zscore_exit_mode: "live",
}),
/DCA strategy profiles are only supported on firstrade/,
/DCA strategy profiles are not supported on ibkr/,
);
assert.throws(
() => __test.normalizeSwitchInputs({
Expand Down Expand Up @@ -690,13 +705,11 @@ const normalizedReserveClearInputs = __test.normalizeSwitchInputs({
IBKR_RESERVED_CASH_RATIO: "",
}),
});
assert.equal(
normalizedReserveClearInputs.extra_variables_json,
JSON.stringify({
IBKR_MIN_RESERVED_CASH_USD: "",
IBKR_RESERVED_CASH_RATIO: "",
}),
);
assert.deepEqual(JSON.parse(normalizedReserveClearInputs.extra_variables_json), {
IBKR_MIN_RESERVED_CASH_USD: "",
IBKR_RESERVED_CASH_RATIO: "",
cash_only_execution_mode: "enabled",
});
assert.throws(
() => __test.normalizeSwitchInputs({
platform: "ibkr",
Expand Down
13 changes: 10 additions & 3 deletions web/strategy-switch-console/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -2105,6 +2105,7 @@ function hasValidStrategySelection(platform = state.selected) {
optionOverlayChanged: optionOverlay.changed,
cashOnlyChanged: cashOnly.changed,
dcaChanged: dca.changed,
ibitZscoreExitChanged: ibitZscoreExit.changed,
runtimeTarget,
reserve,
income,
Expand All @@ -2126,7 +2127,8 @@ function hasValidStrategySelection(platform = state.selected) {
changes.incomeLayerChanged ||
changes.optionOverlayChanged ||
changes.cashOnlyChanged ||
changes.dcaChanged,
changes.dcaChanged ||
changes.ibitZscoreExitChanged,
);
}

Expand Down Expand Up @@ -2198,6 +2200,9 @@ function hasValidStrategySelection(platform = state.selected) {
if (dcaSupported(inputs.strategy_profile)) {
rows.push([t("currentDca"), currentDcaText(state.selected, account, inputs.strategy_profile)]);
}
if (ibitZscoreExitSupported(inputs.strategy_profile)) {
rows.push([t("currentIbitZscoreExit"), currentIbitZscoreExitText(state.selected, account, inputs.strategy_profile)]);
}

if (changes.reserveCashChanged) {
rows.push([t("pendingReservedCashPolicy"), pendingReservedCashPolicyText(inputs, state.selected, account), "pending"]);
Expand All @@ -2214,7 +2219,10 @@ function hasValidStrategySelection(platform = state.selected) {
if (changes.dcaChanged) {
rows.push([t("pendingDca"), pendingDcaText(inputs, state.selected, account), "pending"]);
}

if (changes.ibitZscoreExitChanged) {
rows.push([t("pendingIbitZscoreExit"), pendingIbitZscoreExitText(inputs, state.selected, account), "pending"]);
}

if (changes.modeChanged) {
rows.push([t("pendingMode"), modeLabel(inputs.execution_mode), "pending"]);
}
Expand Down Expand Up @@ -3051,4 +3059,3 @@ function hasValidStrategySelection(platform = state.selected) {
await refreshStrategyProfiles();
await refreshSession();
}

2 changes: 1 addition & 1 deletion web/strategy-switch-console/app_js.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion web/strategy-switch-console/page_asset.js

Large diffs are not rendered by default.

Loading
Loading