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
9 changes: 5 additions & 4 deletions .github/workflows/sync-cloud-run-env.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
IBKR_MIN_RESERVED_CASH_USD: ${{ vars.IBKR_MIN_RESERVED_CASH_USD }}
IBKR_RESERVED_CASH_RATIO: ${{ vars.IBKR_RESERVED_CASH_RATIO }}
IBKR_SAFE_HAVEN_CASH_SUBSTITUTE_THRESHOLD_USD: ${{ vars.IBKR_SAFE_HAVEN_CASH_SUBSTITUTE_THRESHOLD_USD }}
CRISIS_ALERT_GOOGLE_VOICE_GATEWAY: ${{ vars.CRISIS_ALERT_GOOGLE_VOICE_GATEWAY }}
CRISIS_ALERT_GOOGLE_VOICE_RECIPIENTS: ${{ vars.CRISIS_ALERT_GOOGLE_VOICE_RECIPIENTS }}
CRISIS_ALERT_GOOGLE_VOICE_GMAIL_USER: ${{ vars.CRISIS_ALERT_GOOGLE_VOICE_GMAIL_USER }}
CRISIS_ALERT_GOOGLE_VOICE_GMAIL_APP_PASSWORD_SECRET_NAME: ${{ vars.CRISIS_ALERT_GOOGLE_VOICE_GMAIL_APP_PASSWORD_SECRET_NAME }}
# Strategy-owned defaults continue to come from UsEquityStrategies; this workflow only syncs platform/runtime inputs.
Expand Down Expand Up @@ -268,6 +268,7 @@ jobs:
"IB_GATEWAY_INSTANCE_NAME"
"IB_GATEWAY_MODE"
"CRISIS_ALERT_GOOGLE_VOICE_TO"
"CRISIS_ALERT_GOOGLE_VOICE_GATEWAY"
"CRISIS_ALERT_SMTP_FROM"
"CRISIS_ALERT_SMTP_HOST"
"CRISIS_ALERT_SMTP_PORT"
Expand Down Expand Up @@ -368,10 +369,10 @@ jobs:
remove_env_vars+=("IBKR_RESERVED_CASH_RATIO")
fi

if [ -n "${CRISIS_ALERT_GOOGLE_VOICE_GATEWAY:-}" ]; then
env_pairs+=("CRISIS_ALERT_GOOGLE_VOICE_GATEWAY=${CRISIS_ALERT_GOOGLE_VOICE_GATEWAY}")
if [ -n "${CRISIS_ALERT_GOOGLE_VOICE_RECIPIENTS:-}" ]; then
env_pairs+=("CRISIS_ALERT_GOOGLE_VOICE_RECIPIENTS=${CRISIS_ALERT_GOOGLE_VOICE_RECIPIENTS}")
else
remove_env_vars+=("CRISIS_ALERT_GOOGLE_VOICE_GATEWAY")
remove_env_vars+=("CRISIS_ALERT_GOOGLE_VOICE_RECIPIENTS")
fi

if [ -n "${CRISIS_ALERT_GOOGLE_VOICE_GMAIL_USER:-}" ]; then
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,9 @@ For IBKR, keep `paper` as a single account-group entry. If you later add live ac
| `TELEGRAM_TOKEN` | Yes | Telegram bot token. For Cloud Run, prefer a Secret Manager reference instead of a literal env var. |
| `GLOBAL_TELEGRAM_CHAT_ID` | Yes | Telegram chat ID used by this service. |
| `NOTIFY_LANG` | No | `en` (default) or `zh` |
| `CRISIS_ALERT_GOOGLE_VOICE_GATEWAY` | No | Comma/semicolon/newline-separated Google Voice SMS gateway recipients, usually ending in `@txt.voice.google.com`. |
| `CRISIS_ALERT_GOOGLE_VOICE_GMAIL_USER` | No | Gmail address used to send Google Voice gateway alerts. |
| `CRISIS_ALERT_GOOGLE_VOICE_GMAIL_APP_PASSWORD` | No | Gmail App Password for Google Voice gateway alerts. For Cloud Run, prefer `CRISIS_ALERT_GOOGLE_VOICE_GMAIL_APP_PASSWORD_SECRET_NAME` in env sync. |
| `CRISIS_ALERT_GOOGLE_VOICE_RECIPIENTS` | No | Comma/semicolon/newline-separated email-form recipients. Use a normal mailbox for email-only delivery, or a Google Voice mailbox/address to also trigger GV prompts. |
| `CRISIS_ALERT_GOOGLE_VOICE_GMAIL_USER` | No | Gmail address used as the sender for Google Voice notification mail. |
| `CRISIS_ALERT_GOOGLE_VOICE_GMAIL_APP_PASSWORD` | No | Gmail App Password for the sender account. For Cloud Run, prefer `CRISIS_ALERT_GOOGLE_VOICE_GMAIL_APP_PASSWORD_SECRET_NAME` in env sync. |

The selected account-group entry must provide at least:

Expand Down Expand Up @@ -358,9 +358,9 @@ IBKR 账户
| `TELEGRAM_TOKEN` | 是 | Telegram 机器人 Token。Cloud Run 上更推荐走 Secret Manager 引用,不要直接写成明文 env。 |
| `GLOBAL_TELEGRAM_CHAT_ID` | 是 | 这个服务使用的 Telegram Chat ID。 |
| `NOTIFY_LANG` | 否 | `en`(默认)或 `zh` |
| `CRISIS_ALERT_GOOGLE_VOICE_GATEWAY` | 否 | Google Voice 短信网关收件人,通常以 `@txt.voice.google.com` 结尾,支持逗号、分号或换行分隔。 |
| `CRISIS_ALERT_GOOGLE_VOICE_RECIPIENTS` | 否 | 通知收件邮箱。普通邮箱只收邮件;Google Voice 邮箱/地址会额外触发 GV 提醒。支持逗号、分号或换行分隔。 |
| `CRISIS_ALERT_GOOGLE_VOICE_GMAIL_USER` | 否 | Google Voice 通知使用的 Gmail 地址。 |
| `CRISIS_ALERT_GOOGLE_VOICE_GMAIL_APP_PASSWORD` | 否 | Google Voice 通知使用的 Gmail App Password。Cloud Run env sync 建议配置 `CRISIS_ALERT_GOOGLE_VOICE_GMAIL_APP_PASSWORD_SECRET_NAME`。 |
| `CRISIS_ALERT_GOOGLE_VOICE_GMAIL_APP_PASSWORD` | 否 | 发送方 Gmail 账号的 App Password。Cloud Run env sync 建议配置 `CRISIS_ALERT_GOOGLE_VOICE_GMAIL_APP_PASSWORD_SECRET_NAME`。 |

选中的账号组配置里,至少要有:

Expand Down
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
flask
gunicorn
quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@34a2c74deb7aafef0f6f4b278444d7b0efb76794
us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@861eaedc1caecf1e33ff12f55bbe9af87a221df1
quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@705667fbb88b743eb83e858b1cc42fe9ebc3a87a
us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@aca4e1449e9e87e0222b8a1a5e0dd84f822d516c
pandas
numpy
requests
Expand Down
6 changes: 3 additions & 3 deletions runtime_config_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class PlatformRuntimeSettings:
tg_chat_id: str | None = None
notify_lang: str = "en"
strategy_plugin_mounts_json: str | None = None
crisis_alert_google_voice_gateway: tuple[str, ...] = ()
crisis_alert_google_voice_recipients: tuple[str, ...] = ()
crisis_alert_google_voice_gmail_user: str | None = None
crisis_alert_google_voice_gmail_app_password: str | None = None
runtime_target: RuntimeTarget | None = None
Expand Down Expand Up @@ -183,8 +183,8 @@ def load_platform_runtime_settings(
os.getenv("IBKR_STRATEGY_PLUGIN_MOUNTS_JSON")
or os.getenv("STRATEGY_PLUGIN_MOUNTS_JSON")
),
crisis_alert_google_voice_gateway=split_env_list(
os.getenv("CRISIS_ALERT_GOOGLE_VOICE_GATEWAY")
crisis_alert_google_voice_recipients=split_env_list(
os.getenv("CRISIS_ALERT_GOOGLE_VOICE_RECIPIENTS")
),
crisis_alert_google_voice_gmail_user=first_non_empty(
os.getenv("CRISIS_ALERT_GOOGLE_VOICE_GMAIL_USER")
Expand Down
2 changes: 1 addition & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def load_strategy_module(**env_overrides):
),
"IB_ACCOUNT_GROUP_CONFIG_SECRET_NAME": None,
"GLOBAL_TELEGRAM_CHAT_ID": None,
"CRISIS_ALERT_GOOGLE_VOICE_GATEWAY": None,
"CRISIS_ALERT_GOOGLE_VOICE_RECIPIENTS": None,
"CRISIS_ALERT_GOOGLE_VOICE_GMAIL_USER": None,
"CRISIS_ALERT_GOOGLE_VOICE_GMAIL_APP_PASSWORD": None,
}
Expand Down
6 changes: 3 additions & 3 deletions tests/test_runtime_config_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ def test_load_platform_runtime_settings_uses_minimal_group_config(monkeypatch):
assert settings.tg_token is None
assert settings.tg_chat_id is None
assert settings.strategy_plugin_mounts_json is None
assert settings.crisis_alert_google_voice_gateway == ()
assert settings.crisis_alert_google_voice_recipients == ()
assert settings.crisis_alert_google_voice_gmail_user is None
assert settings.crisis_alert_google_voice_gmail_app_password is None

Expand Down Expand Up @@ -207,13 +207,13 @@ def test_load_platform_runtime_settings_reads_crisis_alert_google_voice_config(m
monkeypatch.setenv("RUNTIME_TARGET_JSON", runtime_target_json(SAMPLE_STRATEGY_PROFILE))
monkeypatch.setenv("ACCOUNT_GROUP", "paper")
monkeypatch.setenv("IB_ACCOUNT_GROUP_CONFIG_JSON", MINIMAL_GROUP_JSON)
monkeypatch.setenv("CRISIS_ALERT_GOOGLE_VOICE_GATEWAY", "gateway@txt.voice.google.com")
monkeypatch.setenv("CRISIS_ALERT_GOOGLE_VOICE_RECIPIENTS", "alerts@example.com; voice@example.com")
monkeypatch.setenv("CRISIS_ALERT_GOOGLE_VOICE_GMAIL_USER", "sender@gmail.com")
monkeypatch.setenv("CRISIS_ALERT_GOOGLE_VOICE_GMAIL_APP_PASSWORD", "secret")

settings = load_platform_runtime_settings(project_id_resolver=lambda: "project-1")

assert settings.crisis_alert_google_voice_gateway == ("gateway@txt.voice.google.com",)
assert settings.crisis_alert_google_voice_recipients == ("alerts@example.com", "voice@example.com")
assert settings.crisis_alert_google_voice_gmail_user == "sender@gmail.com"
assert settings.crisis_alert_google_voice_gmail_app_password == "secret"

Expand Down
7 changes: 4 additions & 3 deletions tests/test_sync_cloud_run_env_workflow.sh
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ grep -Fq 'IBKR_PAPER_LIQUIDATE_ONLY: ${{ vars.IBKR_PAPER_LIQUIDATE_ONLY }}' "$wo
grep -Fq 'IBKR_MIN_RESERVED_CASH_USD: ${{ vars.IBKR_MIN_RESERVED_CASH_USD }}' "$workflow_file"
grep -Fq 'IBKR_RESERVED_CASH_RATIO: ${{ vars.IBKR_RESERVED_CASH_RATIO }}' "$workflow_file"
grep -Fq 'IBKR_SAFE_HAVEN_CASH_SUBSTITUTE_THRESHOLD_USD: ${{ vars.IBKR_SAFE_HAVEN_CASH_SUBSTITUTE_THRESHOLD_USD }}' "$workflow_file"
grep -Fq 'CRISIS_ALERT_GOOGLE_VOICE_GATEWAY: ${{ vars.CRISIS_ALERT_GOOGLE_VOICE_GATEWAY }}' "$workflow_file"
grep -Fq 'CRISIS_ALERT_GOOGLE_VOICE_RECIPIENTS: ${{ vars.CRISIS_ALERT_GOOGLE_VOICE_RECIPIENTS }}' "$workflow_file"
grep -Fq 'CRISIS_ALERT_GOOGLE_VOICE_GMAIL_USER: ${{ vars.CRISIS_ALERT_GOOGLE_VOICE_GMAIL_USER }}' "$workflow_file"
grep -Fq 'CRISIS_ALERT_GOOGLE_VOICE_GMAIL_APP_PASSWORD_SECRET_NAME: ${{ vars.CRISIS_ALERT_GOOGLE_VOICE_GMAIL_APP_PASSWORD_SECRET_NAME }}' "$workflow_file"
grep -Fq 'IB_GATEWAY_ZONE: ${{ vars.IB_GATEWAY_ZONE }}' "$workflow_file"
Expand Down Expand Up @@ -91,7 +91,7 @@ grep -Fq 'env_pairs+=("IBKR_PAPER_LIQUIDATE_ONLY=${IBKR_PAPER_LIQUIDATE_ONLY}")'
grep -Fq 'env_pairs+=("IBKR_MIN_RESERVED_CASH_USD=${IBKR_MIN_RESERVED_CASH_USD}")' "$workflow_file"
grep -Fq 'env_pairs+=("IBKR_RESERVED_CASH_RATIO=${IBKR_RESERVED_CASH_RATIO}")' "$workflow_file"
grep -Fq 'env_pairs+=("IBKR_SAFE_HAVEN_CASH_SUBSTITUTE_THRESHOLD_USD=${IBKR_SAFE_HAVEN_CASH_SUBSTITUTE_THRESHOLD_USD}")' "$workflow_file"
grep -Fq 'env_pairs+=("CRISIS_ALERT_GOOGLE_VOICE_GATEWAY=${CRISIS_ALERT_GOOGLE_VOICE_GATEWAY}")' "$workflow_file"
grep -Fq 'env_pairs+=("CRISIS_ALERT_GOOGLE_VOICE_RECIPIENTS=${CRISIS_ALERT_GOOGLE_VOICE_RECIPIENTS}")' "$workflow_file"
grep -Fq 'env_pairs+=("CRISIS_ALERT_GOOGLE_VOICE_GMAIL_USER=${CRISIS_ALERT_GOOGLE_VOICE_GMAIL_USER}")' "$workflow_file"
grep -Fq 'env_pairs+=("CRISIS_ALERT_GOOGLE_VOICE_GMAIL_APP_PASSWORD=${CRISIS_ALERT_GOOGLE_VOICE_GMAIL_APP_PASSWORD}")' "$workflow_file"
grep -Fq 'remove_env_vars+=("IBKR_FEATURE_SNAPSHOT_PATH")' "$workflow_file"
Expand All @@ -104,10 +104,11 @@ grep -Fq 'remove_env_vars+=("IBKR_PAPER_LIQUIDATE_ONLY")' "$workflow_file"
grep -Fq 'remove_env_vars+=("IBKR_MIN_RESERVED_CASH_USD")' "$workflow_file"
grep -Fq 'remove_env_vars+=("IBKR_RESERVED_CASH_RATIO")' "$workflow_file"
grep -Fq 'remove_env_vars+=("IBKR_SAFE_HAVEN_CASH_SUBSTITUTE_THRESHOLD_USD")' "$workflow_file"
grep -Fq 'remove_env_vars+=("CRISIS_ALERT_GOOGLE_VOICE_GATEWAY")' "$workflow_file"
grep -Fq 'remove_env_vars+=("CRISIS_ALERT_GOOGLE_VOICE_RECIPIENTS")' "$workflow_file"
grep -Fq 'remove_env_vars+=("CRISIS_ALERT_GOOGLE_VOICE_GMAIL_USER")' "$workflow_file"
grep -Fq 'remove_env_vars+=("CRISIS_ALERT_GOOGLE_VOICE_GMAIL_APP_PASSWORD")' "$workflow_file"
grep -Fq '"CRISIS_ALERT_GOOGLE_VOICE_TO"' "$workflow_file"
grep -Fq '"CRISIS_ALERT_GOOGLE_VOICE_GATEWAY"' "$workflow_file"
grep -Fq '"CRISIS_ALERT_SMTP_HOST"' "$workflow_file"
grep -Fq 'secret_pairs+=("TELEGRAM_TOKEN=${TELEGRAM_TOKEN_SECRET_NAME}:latest")' "$workflow_file"
grep -Fq 'secret_pairs+=("CRISIS_ALERT_GOOGLE_VOICE_GMAIL_APP_PASSWORD=${CRISIS_ALERT_GOOGLE_VOICE_GMAIL_APP_PASSWORD_SECRET_NAME}:latest")' "$workflow_file"
Expand Down